【问题标题】:Group list of tuples by first element, get average of second element按第一个元素分组元组列表,获取第二个元素的平均值
【发布时间】:2019-07-24 22:42:39
【问题描述】:

我有一个元组列表,如下所示:

val list = List((1, 20), (2, 20), (1, 30), (2, 40), (2, 60))

我想将它映射到一个元组列表,其中:

第一个元素是唯一的。
第二个元素是从具有相同第一个值的元组中平均得出的。

即对于上面的列表,映射到:List((1, 25), (2, 40))

我想我可以这样做:

list.groupBy(_._1)
  .map { case (key, value) =>
    (key, value.map(_._2).sum / value.length)}.toList

但是在这样的地图之间进行转换似乎是不必要的冗长和昂贵的。有没有更好的方法?

【问题讨论】:

  • 不是真的,想想你脑子里的算法,第一步是对事物进行分组,这需要一个中间数据结构。但是,如果您自己编写一个尾递归函数,则可以进行一些优化,例如在进行分组的同时跟踪总和和计数。
  • 您可以使用 mapValues 简化“大地图”:list.groupBy( _._1 ).mapValues { value => value.map(_._2).sum / value.length }.toList

标签: scala


【解决方案1】:

您可能会使用Scala 2.13groupMap 使其稍微不那么冗长:

// val tuples = List((1, 20), (2, 20), (1, 30), (2, 40), (2, 60))
tuples.groupMap(_._1)(_._2).mapValues(vs => vs.sum / vs.size).toList
// List((1, 25), (2, 40))

注意groupMap的中间结果:

tuples.groupMap(_._1)(_._2)
// Map(1 -> List(20, 30), 2 -> List(20, 40, 60))

【讨论】:

  • 为什么不groupMapReduce(_._1) { case (_, v) => (v, 1) } (combineTuples)?一次计算总和和计数,作为一个元组。然后view.mapValues { case (sum, count) => sum / count }.toList.
  • 实际上,您可以在 map 步骤中准备一个 reduce 步骤,并为每个键生成一个总和和一个计数作为 groupMapReduce 的输出。如果每个键的 nbr 值变得重要,那么groupMapReduce 解决方案的性能会更高。否则,为了简单起见,我会使用groupMap。这可能看起来像:tuples.groupMapReduce(_._1) { case (_, v) => (v, 1) }{ case (a, b) => (a._1 + b._1, a._2 + 1) }.mapValues { case (sum, count) => sum/count }.toList 在这一点上,命令式解决方案实际上可能看起来更好。
【解决方案2】:

这可以使用groupBygroupMap 来完成

list.groupBy(_._1).view.mapValues(value => value.map(_._2).sum / value.length).toList

输出: List((1,25), (2,40))

list.groupMap(_._1)(_._2).view.mapValues(value => value.sum / value.size).toList

输出: List((1,25), (2,40))

 list.groupMap(_._1)(_._2)

输出: Map(1 -> List(20, 30), 2 -> List(20, 40, 60))

 list.groupBy(_._1)

输出: HashMap(1 -> List((1,20), (1,30)), 2 -> List((2,20), (2,40), (2,60)))

  list.groupBy(_._2)

输出: HashMap(20 -> List((1,20), (2,20)), 60 -> List((2,60)), 40 -> List((2,40)), 30 -> List((1,30)))

【讨论】:

    猜你喜欢
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 2019-04-19
    • 1970-01-01
    • 2013-04-29
    相关资源
    最近更新 更多