Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/silverlight/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基于Scala映射类型的模式匹配_Scala_Map_Pattern Matching - Fatal编程技术网

基于Scala映射类型的模式匹配

基于Scala映射类型的模式匹配,scala,map,pattern-matching,Scala,Map,Pattern Matching,假设我在Scala中有一个映射[String,String] 我想匹配地图中的全套键值对 这样的事情应该是可能的 val record = Map("amenity" -> "restaurant", "cuisine" -> "chinese", "name" -> "Golden Palace") record match { case Map("amenity" -> "restaurant", "cuisine" -> "chinese") =>

假设我在Scala中有一个
映射[String,String]

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

这样的事情应该是可能的

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"
}
编译器抱怨thulsy:

错误:值映射不是case类构造函数,也没有unapply/unplyseq方法


当前,在
映射中对键值组合进行模式匹配的最佳方法是什么?

您只需查找有问题的值,将它们粘贴在元组中,然后对其进行模式匹配:

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"
}
或者,您可以进行一些嵌套匹配,这可能会更干净一些:

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"
}

请注意,
map.get(key)
返回一个
选项[ValueType]
(在本例中,ValueType将是String),因此如果map中不存在键,它将返回
None
,而不是抛出异常。

模式匹配不是您想要的。您要查找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 ) )
编辑:添加匹配条件

通过这种方式,您可以轻松添加匹配条件

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
val record=Map(“舒适性”->“餐厅”、“美食”->“中式”、“名称”->“金殿”)
案例类FoodMatcher(kv:Map[String,String],输出:String)
val matchers=列表(
餐饮部(地图(“便利设施”->“餐厅”、“美食”->“中式”)、“中式餐厅,车车”),
餐饮经营者(地图(“便利设施”->“餐厅”、“美食”->“意大利菜”)、“意大利餐厅,妈妈咪呀”)
)
为了{
匹配器匹配器.kv(键)=记录(键))
}产量匹配器
给出:


列表(中餐厅,che-che)

您可以使用
平面图
提取您感兴趣的值,然后与它们进行匹配:

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"
}
请参见上的#1

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

请注意,即使键可能不在映射中,上述方法也会起作用,但如果键共享一些值,则您可能希望使用
map
而不是
flatMap
,并在值列表中明确显示
some
/
None
。例如,在这种情况下,如果“舒适性”可能不存在,“烹饪”的价值可能是“餐厅”(在这个例子中很愚蠢,但在另一个上下文中可能不是),那么
case“restaurant”:
将是不明确的


另外,值得注意的是,
case“restaurant”:“chinese”:
case List(“restaurant”、“chinese”)
的效率略高,因为后者不需要检查这两个元素之后是否没有更多的元素

我发现以下使用提取器的解决方案与case类最为相似。不过,大部分是肉汁

object Ex {
   def unapply(m: Map[String, Int]) : Option[(Int,Int) = for {
       a <- m.get("A")
       b <- m.get("B")
   } yield (a, b)
}

val ms = List(Map("A" -> 1, "B" -> 2),
    Map("C" -> 1),
    Map("C" -> 1, "A" -> 2, "B" -> 3),
    Map("C" -> 1, "A" -> 1, "B" -> 2)
    )  

ms.map {
    case Ex(1, 2) => println("match")
    case _        => println("nomatch")
}
objectex{
def unapply(m:Map[String,Int]):选项[(Int,Int)=for{
a(2),,
地图(“C”->1),
地图(“C”->1,“A”->2,“B”->3),
地图(“C”->1,“A”->1,“B”->2)
)  
map女士{
案例Ex(1,2)=>println(“匹配”)
案例=>println(“nomatch”)
}

因为,尽管我同意所有其他答案都非常合理,但我有兴趣看看是否真的有一种使用地图进行模式匹配的方法,我将以下内容放在一起。它使用与顶部答案相同的逻辑来确定匹配

class MapSubsetMatcher[Key, Value](matcher: Map[Key, Value]) {
  def unapply(arg: Map[Key, Value]): Option[Map[Key, Value]] = {
    if (matcher.keys.forall(
      key => arg.contains(key) && matcher(key) == arg(key)
    ))
      Some(arg)
    else
      None
  }
}

val chineseRestaurant = new MapSubsetMatcher(Map("amenity" -> "restaurant", "cuisine" -> "chinese"))
val italianRestaurant = new MapSubsetMatcher(Map("amenity" -> "restaurant", "cuisine" -> "italian"))
val greatPizza = new MapSubsetMatcher(Map("pizza_rating" -> "excellent"))

val record = Map("amenity" -> "restaurant", "cuisine" -> "chinese", "name" -> "Golden Palace")
val frankies = Map("amenity" -> "restaurant", "cuisine" -> "italian", "name" -> "Frankie's", "pizza_rating" -> "excellent")


def matcher(x: Any): String = x match {
  case greatPizza(_) => "It's really good, you should go there."
  case chineseRestaurant(matchedMap) => "a Chinese restaurant called " +
    matchedMap.getOrElse("name", "INSERT NAME HERE")
  case italianRestaurant(_) => "an Italian restaurant"
  case _ => "something else entirely"
}

matcher(record)
// a Chinese restaurant called Golden Palace
matcher(frankies)
// It's really good, you should go there.

另一个版本要求您指定要提取的键,并允许您匹配值,如下所示:

包含[K](ks:K*)的类映射{
def unplyseq[V](m:Map[K,V]):选项[Seq[V]=if(ks.forall(m.contains))Some(ks.Map(m))else无
}
val MapIncluding GABC=新的MapIncluding(“a”、“b”、“c”)
val MAPINCLUDEGAANDB=新的MAPINCLUDENG(“a”、“b”)
地图(“a”->1,“b”->2)匹配{
案例MAPINCLUDEGABC(a,b,c)=>println(“不应该发生”)
案例MAPINCLUDEGAANDB(1,b)=>println(s“图中b的值为$b”)
}

就像DaoWen的回答一样,你不能用任意值来匹配。我不明白,Guillaume——你能详细说明一下吗?好的,我想我明白你的意思。假设PartialFunction是一个参数,而不是内联代码,你不知道它依赖于哪个键。那么你就不知道平面映射什么了结束。在这种情况下,您将不使用partialfunction;您将使用
作为参数,并按上述方法执行
if
class MapSubsetMatcher[Key, Value](matcher: Map[Key, Value]) {
  def unapply(arg: Map[Key, Value]): Option[Map[Key, Value]] = {
    if (matcher.keys.forall(
      key => arg.contains(key) && matcher(key) == arg(key)
    ))
      Some(arg)
    else
      None
  }
}

val chineseRestaurant = new MapSubsetMatcher(Map("amenity" -> "restaurant", "cuisine" -> "chinese"))
val italianRestaurant = new MapSubsetMatcher(Map("amenity" -> "restaurant", "cuisine" -> "italian"))
val greatPizza = new MapSubsetMatcher(Map("pizza_rating" -> "excellent"))

val record = Map("amenity" -> "restaurant", "cuisine" -> "chinese", "name" -> "Golden Palace")
val frankies = Map("amenity" -> "restaurant", "cuisine" -> "italian", "name" -> "Frankie's", "pizza_rating" -> "excellent")


def matcher(x: Any): String = x match {
  case greatPizza(_) => "It's really good, you should go there."
  case chineseRestaurant(matchedMap) => "a Chinese restaurant called " +
    matchedMap.getOrElse("name", "INSERT NAME HERE")
  case italianRestaurant(_) => "an Italian restaurant"
  case _ => "something else entirely"
}

matcher(record)
// a Chinese restaurant called Golden Palace
matcher(frankies)
// It's really good, you should go there.