与Scala Map类型匹配的模式

Tom*_*ris 21 scala map pattern-matching

想象一下我Map[String, String]在Scala中有一个.

我想匹配地图中的全套键值对.

这样的事情应该是可能的

val record = Map("amenity" -> "restaurant", "cuisine" -> "chinese", "name" -> "Golden Palace")
record match {
    case Map("amenity" -> "restaurant", "cuisine" -> "chinese") => "a Chinese restaurant"
    case Map("amenity" -> "restaurant", "cuisine" -> "italian") => "an Italian restaurant"
    case Map("amenity" -> "restaurant") => "some other restaurant"
    case _ => "something else entirely"
}
Run Code Online (Sandbox Code Playgroud)

编译器抱怨说:

error: value Map is not a case class constructor, nor does it have an unapply/unapplySeq method

目前什么是模式匹配键值组合的最佳方法Map

Ami*_*ico 11

您可以flatMap用来提取您感兴趣的值,然后匹配它们:

List("amenity","cuisine") flatMap ( record get _ ) match {
  case "restaurant"::"chinese"::_ => "a Chinese restaurant"
  case "restaurant"::"italian"::_ => "an Italian restaurant"
  case "restaurant"::_            => "some other restaurant"
  case _                          => "something else entirely"
}
Run Code Online (Sandbox Code Playgroud)

请参阅此代码段页面上的#1 .

您可以检查任意列表是否具有如下特定:

if ( ( keys flatMap ( record get _ ) ) == values ) ...
Run Code Online (Sandbox Code Playgroud)

请注意,即使键可以在地图中不存在,上述方法仍然有效,但如果键共享某些值,您可能希望使用map而不是在值列表中flatMap使用Some/ 显式键None.例如,在这种情况下,如果"美食"可能不存在且"美食"的价值可能是"餐馆"(对于这个例子来说很愚蠢,但也许不在另一个背景下),那么case "restaurant"::_就会含糊不清.

此外,值得注意的是,case "restaurant"::"chinese"::_效率略高于case List("restaurant","chinese")后者不必要地检查在这两者之后没有更多元素.


Dao*_*Wen 7

你可以只查找有问题的值,将它们粘贴在一个元组中,并在其上进行模式匹配:

val record = Map("amenity" -> "restaurant", "cuisine" -> "chinese", "name" -> "Golden Palace")
(record.get("amenity"), record.get("cuisine")) match {
    case (Some("restaurant"), Some("chinese")) => "a Chinese restaurant"
    case (Some("restaurant"), Some("italian")) => "an Italian restaurant"
    case (Some("restaurant"), _) => "some other restaurant"
    case _ => "something else entirely"
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以执行一些嵌套匹配,这可能会更清晰:

val record = Map("amenity" -> "restaurant", "cuisine" -> "chinese", "name" -> "Golden Palace")
record.get("amenity") match {
  case Some("restaurant") => record.get("cuisine") match {
    case Some("chinese") => "a Chinese restaurant"
    case Some("italian") => "an Italian restaurant"
    case _ => "some other restaurant"
  }
  case _ => "something else entirely"
}
Run Code Online (Sandbox Code Playgroud)

请注意,map.get(key)返回一个Option[ValueType](在这种情况下ValueType将是String),因此None如果地图中不存在该键,它将返回而不是抛出异常.


Gui*_*ssé 6

模式匹配不是您想要的。您要查找A是否完全包含B

val record = Map("amenity" -> "restaurant", "cuisine" -> "chinese", "name" -> "Golden Palace")
val expect = Map("amenity" -> "restaurant", "cuisine" -> "chinese")
expect.keys.forall( key => expect( key ) == record( key ) )
Run Code Online (Sandbox Code Playgroud)

编辑:添加匹配条件

这样,您可以轻松添加匹配条件

val record = Map("amenity" -> "restaurant", "cuisine" -> "chinese", "name" -> "Golden Palace")

case class FoodMatcher( kv: Map[String,String], output: String )

val matchers = List( 
    FoodMatcher(  Map("amenity" -> "restaurant", "cuisine" -> "chinese"), "chinese restaurant, che che" ),
    FoodMatcher(  Map("amenity" -> "restaurant", "cuisine" -> "italian"), "italian restaurant, mama mia" )
)

for {
    matcher <- matchers if matcher.kv.keys.forall( key => matcher.kv( key ) == record( key ) )
} yield matcher.output
Run Code Online (Sandbox Code Playgroud)

给出:

List(chinese restaurant, che che)