You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Scala <=2.12中为Traversable[(K, V)]编写通用groupByKey方法

实现保留输入集合类型的groupByKey函数

我懂你想要的效果——就是让groupByKey能像标准库的groupBy那样,返回和输入完全一致的集合类型,而不是固定的Traversable。咱们一步步来解决这个问题:

首先,你提到的针对特定集合的实现确实简洁直观:

def groupByKey[K, V]( pairs: List[(K, V)] ): Map[K, List[V]] = pairs
 .groupBy(_._1)
 .mapValues(_.map(_._2))

但泛化后的版本虽然支持更多输入类型,返回的Traversable却不够灵活:

def groupByKey[K, V]( pairs: Traversable[(K, V)] ): Map[K, Traversable[V]] = pairs
 .groupBy(_._1)
 .mapValues(_.map(_._2))

要实现“和输入同类型”的目标,咱们可以借助Scala的BuildFrom类型类——这正是标准库groupBy能保留集合类型的核心机制。下面是完整的实现:

import scala.collection.generic.BuildFrom
import scala.collection.TraversableLike

def groupByKey[K, V, C[T] <: TraversableLike[T, C[T]]](
  pairs: C[(K, V)]
)(implicit bf: BuildFrom[C[(K, V)], V, C[V]]): Map[K, C[V]] = {
  pairs.groupBy(_._1).map { case (key, values) =>
    key -> values.map(_._2)(bf)
  }
}

简单解释下这个实现:

  • C[T] <: TraversableLike[T, C[T]]用来约束输入集合类型,确保它是可遍历的,并且能生成自身类型的新实例。
  • BuildFrom隐式参数是关键:它告诉Scala如何从输入的C[(K, V)],构建出元素类型为V的C[V]集合,保证输出和输入的集合类型完全匹配。
  • 调用map(_._2)时显式传入bf构建器,让返回结果不再是默认的Traversable[V],而是和输入一致的C[V]。

现在不管你传入List、Vector还是Seq,返回的Map里的值都会是对应的集合类型:

val listPairs = List(("a", 1), ("b", 2), ("a", 3))
val groupedList = groupByKey(listPairs) // 类型是Map[String, List[Int]]

val vectorPairs = Vector(("x", 10), ("y", 20), ("x", 30))
val groupedVector = groupByKey(vectorPairs) // 类型是Map[String, Vector[Int]]

这样就完美满足你的需求啦!

内容的提问来源于stack exchange,提问作者Robert Elliot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 12:32:47