Scala:元组的分组列表

  • 本文关键字:列表 元组 Scala 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 } 

这是有效的,但我相信应该有一种更有效的方法。。。

这与这个问题类似。基本上,正如@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)
}

它所做的是,在构建阶段使用可变Map,并首先在可变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作为默认集合类型。

最新更新