2014-02-28 116 views
2

我需要以某種獨特的方式對元組列表進行分組。Scala:分組元組列表

例如,如果我有

val l = List((1,2,3),(4,2,5),(2,3,3),(10,3,2)) 

然後我應該組與第二值的列表,並與該組第一值

映射所以結果應該是

Map(2 -> Set(1,4), 3 -> Set(2,10)) 

到目前爲止,我想出了這個

l groupBy { p => p._2 } mapValues { v => (v map { vv => vv._1 }).toSet } 

這個工程,但我相信應該有一個更有效的方法...

+1

我認爲你的解決方案很好 – serejja

回答

2

這是類似於this question。基本上,正如@serejja所說,你的方法是正確的,也是最簡潔的方法。你可以使用collection.breakOut作爲生成器工廠的說法到最後map,從而節省額外的迭代,以獲得Set類型:

l.groupBy(_._2).mapValues(_.map(_._1)(collection.breakOut): Set[Int]) 

你不應該可能超越這個,除非你真的需要擠壓性能。


否則,這是一般toMultiMap功能可能看起來怎麼樣,它允許你控制值的集合類型:

import collection.generic.CanBuildFrom 
import collection.mutable 

def toMultiMap[A, K, V, Values](xs: TraversableOnce[A]) 
    (key: A => K)(value: A => V) 
    (implicit cbfv: CanBuildFrom[Nothing, V, Values]): Map[K, Values] = { 
    val b = mutable.Map.empty[K, mutable.Builder[V, Values]] 
    xs.foreach { elem => 
    b.getOrElseUpdate(key(elem), cbfv()) += value(elem) 
    } 
    b.map { case (k, vb) => (k, vb.result()) } (collection.breakOut) 
} 

它是什麼,它在創建階段期間使用可變地圖,並且首先收集的值可變爲Builder(構建器由CanBuildFrom實例提供)。對所有輸入元素的迭代完成後,構建器值的可變映射將轉換爲值集合類型的不可變映射(再次使用collection.breakOut技巧來立即獲取所需的輸出集合)。

例:

val l     = List((1,2,3),(4,2,5),(2,3,3),(10,3,2)) 
val v     = toMultiMap(l)(_._2)(_._1) // uses Vector for values 
val s: Map[Int, Set[Int] = toMultiMap(l)(_._2)(_._1) // uses Set for values 

所以註釋的結果類型指示值類型的類型推斷。如果你不註釋結果,Scala會選擇Vector作爲默認的集合類型。