2010-09-09 4 views
6

Что является самым кратким способом Scala для изменения карты? Карта может содержать не уникальные значения.Что является самым кратким способом Scala для изменения карты?

EDIT:

Инверсия Map[A, B] должен дать Map[B, Set[A]] (или MultiMap, что было бы еще лучше).

+3

Определить, что должно произойти, если данное значение присутствует в более чем одной клавиши. –

+0

@ Randall: См. Редактирование. – missingfaktor

ответ

23

Если вы можете потерять дубликаты ключей:

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, только карту к наборам, то:

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

+1 для лаконичности, и для введения меня в mapValues ​​:-) –

+0

лучший запуск был бы более ясным, хотя, например. Карта (1 -> «один», 2 -> «два», 3 -> «два», 4 -> «два») –

+0

@ Родни - Хорошо, ладно, я покажу случай перекрытия! –

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

Edit для осветленных вопрос:

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

Я не уверен, что это квалифицируется как сжато.

+1

+1 для рабочего решения. :-) – missingfaktor

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