2013-04-07 113 views
3

在Scala中將Map[K, V]轉換爲Map[V, Iterable[K]]的最短/慣用方法是什麼?如何在scala中反轉地圖?

+4

雖然這是真的,這個問題重疊外,對其他頂級答案假設地圖被倒置的是一個注入(沒有兩個鍵映射到相同的值)。對於這個問題並非如此,這是一個關鍵的區別。此外,這個問題使用標準術語「反轉」而不是「反轉」。也許這個問題應該改爲「我怎樣才能在Scala中反轉一個非內射映射?」另一個是「我怎樣才能在Scala中反轉一個單射映射?」 – AmigoNico 2013-04-07 18:34:23

回答

7

馬呂斯的解決方案可以使用mapValues被簡化,

m.groupBy(_._2).mapValues(_.map(_._1)) 

樣品REPL會話,

scala> val m = Map(1 -> "foo", 2 -> "foo", 3 -> "bar", 4 -> "bar", 5 -> "baz") 
m: Map[Int,String] = Map(5 -> baz, 1 -> foo, 2 -> foo, 3 -> bar, 4 -> bar) 

scala> m.groupBy(_._2).mapValues(_.map(_._1)) 
res0: Map[String, Iterable[Int]] = Map(baz -> List(5), foo -> List(1, 2), bar -> List(3, 4)) 
3

這應該做的伎倆:

def invert[A, B](m: Map[A, B]): Map[B, Iterable[A]] = { 
    m.groupBy(_._2).map { 
    case (v, kvPairs) => (v, kvPairs.map(_._1)) 
    } 
} 

此迭代在映射中的鍵 - 值對和組使用值的對(_._2爲元組的第二個元素的吸氣劑)。

這爲我們提供了一個列表,其中第一個元素是值,第二個元素是包含原始映射中所有對的序列,其中第二個元素是該值的第二個元素。

最後,對於後面這些對中的每一個,我們只提取序列中的第一個元素 - 從而獲得一個值,以便在原始映射中映射到它的所有鍵。