Scala - 按键减少元组列表

时间:2018-04-30 23:52:47

标签: scala

我有包含userIdpoint的元组列表。我想通过密钥组合或减少此列表。

val points: List[(Int, Double)] = List(
  (1, 1.0),
  (2, 3.2),
  (4, 2.0),
  (1, 4.0),
  (2, 6.8)
)

预期结果应如下所示:

List((1, 5.0), (2, 10.0), (4, 2.0))

我尝试使用groupBymapValue,但收到了错误:

val aggrPoint: Map[Int, Double] = incomes.groupBy(_._1).mapValues(seq => seq.reduce(_._2 + _._2))

Error:(16, 180) type mismatch;
 found   : Double
 required: (Int, Double)

我做错了什么,有没有一种惯用的方法来实现这个目标?

P.S)我发现在Spark aggregateByKey做了这个工作。但是,Scala中是否有内置方法?

3 个答案:

答案 0 :(得分:2)

您可以mapmapValues中的元组sum添加到第二个元素,然后points.groupBy(_._1).mapValues( _.map(_._2).sum ).toList // res1: List[(Int, Double)] = List((2,10.0), (4,2.0), (1,5.0)) ,如下所示:

clr-dg-filter

答案 1 :(得分:2)

  
    

我做错了什么,有没有一种惯用的方法来实现这个目标?

  

让我们一步一步看看你做错了什么 。 (我将使用 REPL

首先让定义点

scala> val points: List[(Int, Double)] = List(
     |   (1, 1.0),
     |   (2, 3.2),
     |   (4, 2.0),
     |   (1, 4.0),
     |   (2, 6.8)
     | )
points: List[(Int, Double)] = List((1,1.0), (2,3.2), (4,2.0), (1,4.0), (2,6.8))

正如您所看到的那样List[Tuple2[Int, Double]]groupBymapValues

scala> points.groupBy(_._1).mapValues(seq => println(seq))
List((2,3.2), (2,6.8))
List((4,2.0))
List((1,1.0), (1,4.0))
res1: scala.collection.immutable.Map[Int,Unit] = Map(2 -> (), 4 -> (), 1 -> ())

您可以再次看到seq对象是List[Tuple2[Int, Double]] ,但只包含分组的元组作为列表

因此,当您应用seq.reduce(_._2 + _._2)时,reduce函数需要两个Tuple2[Int, Double]输入,但输出只有Double 与下一个不匹配seq上的迭代,因为预期输入为Tuple2[Int, Double] 这是主要问题。您所要做的就是匹配reduce函数的输入和输出类型

一种方法是将Tuple2[Int, Double]

匹配
scala> points.groupBy(_._1).mapValues(seq => seq.reduce{(x,y) => (x._1, x._2 + y._2)})
res6: scala.collection.immutable.Map[Int,(Int, Double)] = Map(2 -> (2,10.0), 4 -> (4,2.0), 1 -> (1,5.0))

但这不是您想要的输出,所以您可以从简化的Tuple2[Int, Double] 中提取双倍值

scala> points.groupBy(_._1).mapValues(seq => seq.reduce{(x,y) => (x._1, x._2 + y._2)}._2)
res8: scala.collection.immutable.Map[Int,Double] = Map(2 -> 10.0, 4 -> 2.0, 1 -> 5.0)

或者您可以仅在使用map功能之前使用reduce

scala> points.groupBy(_._1).mapValues(seq => seq.map(_._2).reduce(_ + _))
res3: scala.collection.immutable.Map[Int,Double] = Map(2 -> 10.0, 4 -> 2.0, 1 -> 5.0)

希望解释清楚明白你的错误,你必须明白reduce函数是如何工作的

答案 2 :(得分:0)

使用collect

points.groupBy(_._1).collect{
   case e => e._1 -> e._2.map(_._2).sum
}.toList
//res1: List[(Int, Double)] = List((2,10.0), (4,2.0), (1,5.0))