Scala列表按标题分组求和后顺序错乱,如何修复?
解决Scala分组求和时保留原列表顺序的问题
你的问题核心在于groupBy返回的是无序的Map(Scala 2中默认是HashMap,Scala 3的Map虽改为有序,但为了兼容多版本,最好显式维护顺序),转成List后元素顺序会偏离原列表中标题首次出现的顺序。下面给你两种修复方案,同时还解决了原输入中存在空格导致toInt报错的潜在问题:
方案一:使用LinkedHashMap维护插入顺序(可变集合)
通过LinkedHashMap记录标题的首次出现顺序,在分组求和的同时保留原列表的顺序:
import scala.collection.mutable.LinkedHashMap def sumByTitle(listInput: List[String]): List[String] = { // 先处理每个元素的空格问题,避免toInt报错 val splitItems = listInput.map(_.split(",").map(_.trim)) // 用LinkedHashMap维护标题的出现顺序,同时累加求和 val grouped = splitItems.foldLeft(LinkedHashMap[String, (String, Int, Int)]()) { case (acc, arr) => val title = arr(0) val category = arr(1) val num1 = arr(2).toInt val num2 = arr(3).toInt acc.get(title) match { // 如果标题已存在,累加数值 case Some((cat, sum1, sum2)) => acc.update(title, (cat, sum1 + num1, sum2 + num2)) // 如果标题是第一次出现,初始化条目 case None => acc.put(title, (category, num1, num2)) } acc } // 按LinkedHashMap的顺序转为结果列表 grouped.map { case (title, (cat, sum1, sum2)) => s"$title,$cat,$sum1,$sum2" }.toList }
方案二:先提取标题顺序再生成结果(不可变集合)
如果你偏好不可变集合,可以先提取原列表中标题的去重顺序(保留首次出现的顺序),再按这个顺序从分组结果中生成最终列表:
def sumByTitle(listInput: List[String]): List[String] = { // 处理空格并拆分每个元素 val splitItems = listInput.map(_.split(",").map(_.trim)) // 获取原列表中标题的首次出现顺序(去重) val titleOrder = splitItems.map(_(0)).distinct // 按标题分组 val grouped = splitItems.groupBy(_(0)) // 按照原顺序遍历标题,生成求和结果 titleOrder.map { title => val features = grouped(title) val category = features.head(1) val sumNum1 = features.map(_(2).toInt).sum val sumNum2 = features.map(_(3).toInt).sum s"$title,$category,$sumNum1,$sumNum2" } }
测试验证
用你的输入示例测试:
- 对于
listInput1,两个方案都会返回List("itemA,CATA,5,5", "itemB,CATB,8,11"),顺序和原列表完全一致 - 对于
listInput2,因为每个标题只出现一次,结果顺序完全匹配原输入
另外,原函数未处理输入字符串的空格(比如"itemA,CATA,2,4 "末尾的空格),直接toInt会抛出NumberFormatException,上面的方案都通过trim()处理了这个问题,让代码更健壮。
内容的提问来源于stack exchange,提问作者scalacode
相关产品推荐
相关产品推荐

