What is Scala's most concise way to reverse the map?

What is Scala's most concise way to reverse the map? A map may contain non-unique values.

EDIT:

Canceling Map[A, B] should give Map[B, Set[A]] (or MultiMap, which would be even better).

+6
scala scala-collections
source share
3 answers

If you can lose duplicate keys:

 scala> val map = Map(1->"one", 2->"two", -2->"two") map: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,one), (2,two), (-2,two)) scala> map.map(_ swap) res0: scala.collection.immutable.Map[java.lang.String,Int] = Map((one,1), (two,-2)) 

If you do not need access in the form of a multimap, just a map for sets, then:

 scala> map.groupBy(_._2).mapValues(_.keys.toSet) res1: scala.collection.immutable.Map[ java.lang.String,scala.collection.immutable.Set[Int] ] = Map((one,Set(1)), (two,Set(2, -2))) 

If you insist on getting a MultiMap , then:

 scala> import scala.collection.mutable.{HashMap, Set, MultiMap} scala> ( (new HashMap[String,Set[Int]] with MultiMap[String,Int]) ++= | map.groupBy(_._2).mapValues(Set[Int]() ++= _.keys) ) res2: scala.collection.mutable.HashMap[String,scala.collection.mutable.Set[Int]] with scala.collection.mutable.MultiMap[String,Int] = Map((one,Set(1)), (two,Set(-2, 2))) 
+23
source share
 scala> val m1 = Map(1 -> "one", 2 -> "two", 3 -> "three", 4 -> "four") m1: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,one), (2,two), (3,three), (4,four)) scala> m1.map(pair => pair._2 -> pair._1) res0: scala.collection.immutable.Map[java.lang.String,Int] = Map((one,1), (two,2), (three,3), (four,4)) 

Edit to clarify the issue:

 object RevMap { def main(args: Array[String]): Unit = { val m1 = Map("one" -> 3, "two" -> 3, "three" -> 5, "four" -> 4, "five" -> 5, "six" -> 3) val rm1 = (Map[Int, Set[String]]() /: m1) { (map: Map[Int, Set[String]], pair: (String, Int)) => map + ((pair._2, map.getOrElse(pair._2, Set[String]()) + pair._1)) } printf("m1=%s%nrm1=%s%n", m1, rm1) } } % scala RevMap m1=Map(four -> 4, three -> 5, two -> 3, six -> 3, five -> 4, one -> 3) rm1=Map(4 -> Set(four, five), 5 -> Set(three), 3 -> Set(two, six, one)) 

I am not sure if this is concise.

+4
source share

What about:

  implicit class RichMap[A, B](map: Map[A, Seq[B]]) { import scala.collection.mutable._ def reverse: MultiMap[B, A] = { val result = new HashMap[B, Set[A]] with MultiMap[B, A] map.foreach(kv => kv._2.foreach(result.addBinding(_, kv._1))) result } } 

or

  implicit class RichMap[A, B](map: Map[A, Seq[B]]) { import scala.collection.mutable._ def reverse: MultiMap[B, A] = { val result = new HashMap[B, Set[A]] with MultiMap[B, A] map.foreach{case(k,v) => v.foreach(result.addBinding(_, k))} result } } 
0
source share

All Articles