我有包含userId
和point
的元组列表。我想通过密钥组合或减少此列表。
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))
我尝试使用groupBy
和mapValue
,但收到了错误:
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中是否有内置方法?
答案 0 :(得分:2)
您可以map
将mapValues
中的元组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]]
,groupBy
和mapValues
为
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))