Scala按键归约元组列表问题及报错求助
解决Scala中按userId合并point的问题
你遇到的错误是因为reduce的使用方式不对,咱们一步步拆解问题来解决:
错误原因分析
先看你写的代码:
val aggrPoint: Map[Int, Double] = points.groupBy(_._1).mapValues(seq => seq.reduce(_._2 + _._2))
groupBy(_._1)执行后得到的是Map[Int, List[(Int, Double)]],每个seq都是对应userId的元组列表。而reduce方法要求传入的函数必须接收两个和序列元素同类型的参数,并且返回相同类型的结果——也就是说,你给reduce的函数应该是((Int, Double), (Int, Double)) => (Int, Double),但你写的_._2 + _._2返回的是Double,这就直接导致了类型不匹配的报错。
正确的实现方式
我们的目标是把每个userId对应的所有point值累加,这里有几种简洁的实现方法:
方法1:提取point后直接求和(最推荐)
先把序列里的point值都提取出来,再用Scala内置的sum方法,直观又易读:
val points: List[(Int, Double)] = List( (1, 1.0), (2, 3.2), (4, 2.0), (1, 4.0), (2, 6.8) ) // 先分组再累加每个组的point val aggrPoint: Map[Int, Double] = points.groupBy(_._1).mapValues(seq => seq.map(_._2).sum) // 转换成你需要的List格式 val resultList: List[(Int, Double)] = aggrPoint.toList // 输出结果:List((1,5.0), (2,10.0), (4,2.0))
方法2:修正reduce的用法
如果你一定要用reduce,可以先把元组序列转换成Double序列再操作,或者直接对元组做符合类型要求的reduce:
// 方式A:先转成Double序列再reduce val aggrPoint: Map[Int, Double] = points.groupBy(_._1).mapValues(seq => seq.map(_._2).reduce(_ + _)) // 方式B:直接对元组reduce(groupBy已保证同组userId相同,所以可以放心取第一个元组的userId) val aggrPoint: Map[Int, Double] = points.groupBy(_._1).mapValues(seq => seq.reduce((a, b) => (a._1, a._2 + b._2))._2)
方法3:用foldLeft实现自定义累加
如果后续需要更灵活的累加逻辑(比如加权重、过滤某些值),可以用foldLeft:
val aggrPoint: Map[Int, Double] = points.groupBy(_._1).mapValues(seq => seq.foldLeft(0.0)((total, tuple) => total + tuple._2))
验证结果
不管用哪种方法,最终转换为List后都能得到你预期的结果:
println(resultList) // 输出:List((1,5.0), (2,10.0), (4,2.0))
内容的提问来源于stack exchange,提问作者gyoho
相关产品推荐
相关产品推荐

