Scala如何按属性将List转换为Map并实现价格求和逻辑
原代码问题说明
- 存在语法错误:调用了未定义的
price.add方法,getOrElse的使用不符合参数类型要求 - 逻辑错误:嵌套多层
map/flatten没有必要,最后试图把整个name列表作为Map的key,不符合按单个name分组的需求 - 重复转换:多次对同一个集合做扁平化、映射操作,逻辑冗余
前置修正说明
你提供的样例类定义和测试数据存在不一致问题:样例类中ProductProperty的options字段类型是List[OptionItem],但测试数据里给options传了Some(...),属于编译错误。以下实现会先修正测试数据的Some包裹,和样例类定义对齐,如果你实际场景中options是Option[List[OptionItem]]类型,只需要在取options的时候加个getOrElse(Nil)即可,核心逻辑无需调整。
正确实现方案
Scala 2.13+ 版本(推荐)
直接使用Scala标准库提供的groupMapReduce简化分组聚合操作:
// 修正后的测试数据 val properties = List( ProductProperty(name = "size", value = Some("val1") , options = List(OptionItem(price = 10) , OptionItem(price = 204))), ProductProperty(name = "size", value = Some("val2") , options = List(OptionItem(price = 122) , OptionItem(price = 240))), ProductProperty(name = "color", value = Some("val3") , options = List(OptionItem(price = 101) , OptionItem(price = 204))), ProductProperty(name = "color", value = Some("val13") , options = List(OptionItem(price = 102) , OptionItem(price = 120))), ProductProperty(name = "Quantity", value = Some("ssval3") , options = List(OptionItem(price = 1011) , OptionItem(price = 204))), ProductProperty(name = "Quantity", value = Some("ssval13") , options = List(OptionItem(price = 1102) , OptionItem(price = 1210))) ) // 核心实现 val priceSumMap = properties // 把每个ProductProperty拆成 (属性名, 单个price) 元组,打平为一维列表 .flatMap(prop => prop.options.map(item => (prop.name, item.price))) // 按属性名分组,直接对同组的price求和 .groupMapReduce(_._1)(_._2)(_ + _)
Scala 2.12及更早版本兼容写法
如果使用低版本Scala,没有groupMapReduceAPI,可以用groupBy+mapValues实现:
val priceSumMap = properties .flatMap(prop => prop.options.map(item => (prop.name, item.price))) .groupBy(_._1) .mapValues(_.map(_._2).sum) .toMap
运行结果
执行后得到的Map完全符合需求:
Map("size" -> 576, "color" -> 527, "Quantity" -> 3527)
计算验证:
- size合计:10+204+122+240 = 576
- color合计:101+204+102+120 = 527
- Quantity合计:1011+204+1102+1210 = 3527
内容的提问来源于stack exchange,提问作者VitalyT
相关产品推荐
相关产品推荐

