Tom Morris Tom Morris - 1 month ago 8
Scala Question

Pattern matching against Scala Map type

Imagine I have a

Map[String, String]
in Scala.

I want to match against the full set of key–value pairings in the map.

Something like this ought to be possible

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


The compiler complains thulsy:

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


What currently is the best way to pattern match for key–value combinations in a
Map
?

Answer

Pattern matching is not what you want. You want to find if A fully contains 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 ) )

Edit: adding matching criteria

This way you can add matching criteria easily

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

Gives:

List(chinese restaurant, che che)