Scala实现:对元组列表中相同日期的数值求和
Scala按日期聚合总花费的优雅实现
嗨,这个需求用Scala的函数式集合操作可以非常优雅地解决,完全不用命令式的循环逻辑~
核心思路
我们需要完成两个关键步骤:
- 按日期对原始列表中的元素进行分组
- 对每个日期分组内的金额进行求和,最终转换为目标格式的列表
方案一:使用groupBy + 映射求和(兼容所有Scala版本)
这是最通用的实现方式,不管你用哪个Scala版本都能跑:
def sumByDate(bought: List[(String, Double, String)]): List[(String, Double)] = { bought // 第一步:按日期分组,得到键为日期、值为对应元素列表的Map .groupBy(item => item._3) // 第二步:遍历每个分组,计算总金额并转换为目标元组 .map { case (date, itemsInDate) => val totalAmount = itemsInDate.map(_._2).sum (date, totalAmount) } // 最后把Map转换为List .toList }
方案二:使用groupMapReduce(Scala 2.13+ 推荐)
如果你的项目用的是Scala 2.13及以上版本,推荐用groupMapReduce,它把分组、映射、聚合三个步骤合并成一个操作,代码更简洁高效:
def sumByDate(bought: List[(String, Double, String)]): List[(String, Double)] = { bought // 三个参数分别是:分组键(日期)、元素映射(取金额)、聚合逻辑(求和) .groupMapReduce(_._3)(_._2)(_ + _) .toList }
关于你原来的思路
你之前先提取日期集合再用for推导式的思路其实也能实现,但效率会低一些(每个日期都要重新遍历整个列表过滤求和),如果要改进的话可以写成这样,但还是不如上面的函数式方法优雅:
val dates = bought.map(_._3).toSet.toList val result = for { date <- dates total = bought.filter(_._3 == date).map(_._2).sum } yield (date, total)
以上两种推荐方案都是Scala惯用的函数式风格,只需要一次遍历就能完成聚合,代码简洁易读~
内容的提问来源于stack exchange,提问作者Laura Galera
相关产品推荐
相关产品推荐

