Pattern matching against Scala Map entries

5.5k views Asked by At

Is there any Scala trick to enable pattern matching against map keys? In other words, I'd like to have an extractor that beside the Map instance accepted also a key value that would mean I want this pattern to match only if the matchable value is an instance of Map and there is an entry with the given key in it and the value for this entry be subject to recursive pattern matching.

Something like this:

myMap match {
    case MyMap("a")(a) => // do smth with value a
    case MyMap("b")(MyMap("c")(c)) => // do smth with value c
}

Update:

I've found some way to approach closer to the goal, but it's still not perfect because it implies definition of synthetic key-value-holders:

case class MapKey[K](key: K) {
  def unapply(o: Any) = o match {
    case m: Map[K, _] ⇒ m.get(key)
    case _ ⇒ None
  }
}

val m1 = Map("a" → "aa", "b" → Map("c" → "cc"))
val m2 = Map("a" → "aa", "d" → "dd")

val b = MapKey("b")
val c = MapKey("c")
val d = MapKey("d")

for (m ← List(m1, m2)) m match {
  case b(c(x)) ⇒ println(s"b > c: $x")
  case d(x) ⇒ println(s"d: $x")
}

Similar question: Can extractors be customized with parameters in the body of a case statement (or anywhere else that an extractor would be used)?

Feature request: SI-5435

1

There are 1 answers

2
Bask.ws On

Maybe you are looking for solution that you don't really need? Can't imagine extractors here. You can use PF if you want to match key-value pairs:

val map = Map[String, String]("a" -> "b")

def matchTuple[A,B,C](map: Map[A,B])(pf: PartialFunction[(A,B), C]) = 
  map.collectFirst(pf)

matchTuple(map) {
  case ("a", b) => println("value for a is " + b)
}

Return type is Option[Unit] because we use collectFirst and println