什么是反转Map的最简洁Scala方法?

7
什么是最简洁的Scala方式来反转一个Map?Map可能包含非唯一值。 编辑: Map[A, B]的反转应该给出Map[B,Set[A]](或MultiMap,那会更好)。

3
如果一个给定的值出现在多个键下,定义应该发生什么。 - Randall Schulz
3个回答

24

如果您可以丢弃重复的键:

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))

如果你不想使用multimap来访问,只想要一个映射到集合的map,则可以这样做:

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)))
如果你坚持要使用MultiMap,那么:
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)))

一个更好的起点会更清晰,例如:Map(1->"one", 2->"two",3->"two",4->"two")。 - Rodney Gitzel

4
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))

针对澄清后的问题进行编辑:

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))

我不确定这是否足够简洁。

0

这样怎么样:

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

或者

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接