如何解决Scala从列表转换为具有求和逻辑的属性映射
我是 Scala 的新手,尝试使用如下所示的求和逻辑从列表转换为映射。
case class ProductProperty(name:String,value:Option[String]= None,options:List[OptionItem]=List())
case class OptionItem(title:Option[String],description:Option[String] = None,price:Int)
val properties = List(ProductProperty(name = "size",value = Some("val1"),options = Some(List(OptionItem(price = 10),OptionItem(price = 204))),ProductProperty(name = "size",value = Some("val2"),options = Some(List(OptionItem(price = 122),OptionItem(price = 240))),ProductProperty(name = "color",value = Some("val3"),options = Some(List(OptionItem(price = 101),value = Some("val13"),options = Some(List(OptionItem(price = 102),OptionItem(price = 120))),ProductProperty(name = "Quantity",value = Some("ssval3"),options = Some(List(OptionItem(price = 1011),value = Some("ssval13"),options = Some(List(OptionItem(price = 1102),OptionItem(price = 1210))
)
我需要将其展平并根据其名称和计算出的价格创建新地图。
Map {
"size" -> total price,"color" -> total price,"Quantity" -> total price
}
到目前为止我尝试过的:
val optList = properties.map( list =>
list.map(op => op.options
.flatMap(i => List(ProductProperty(name = op.name,value = Some(i.value)))))
.flatten
)
val totalPrice = price.add(optList.map(list =>
list.map(_.options)
.flatten.map(_.price.getorElse(0)).sum)
.getorElse(0))
Map((optList.map(_.name).getorElse(List())) -> totalPrice)
但这是不正确的。
解决方法
第一个问题是更正样本数据以便编译。
case class OptionItem(title :Option[String] = None,description :Option[String] = None,price :Int)
case class ProductProperty(name :String,value :Option[String] = None,options :List[OptionItem] = List())
val properties =
List(ProductProperty("size",Some("val1"),List(OptionItem(price = 10),OptionItem(price = 204))),ProductProperty("size",Some("val2"),List(OptionItem(price = 122),OptionItem(price = 240))),ProductProperty("color",Some("val3"),List(OptionItem(price = 101),Some("val13"),List(OptionItem(price = 102),OptionItem(price = 120))),ProductProperty("Quantity",Some("ssval3"),List(OptionItem(price = 1011),Some("ssval13"),List(OptionItem(price = 1102),OptionItem(price = 1210))))
之后就是应用groupBy()
、map()
和fold()
或reduce()
的简单问题。 Scala 2.13.x 一次提供所有 3 个。
properties.groupMapReduce(_.name)(_.options.map(_.price).sum)(_+_)
//res0: Map[String,Int] = Map(size -> 576,color -> 527,Quantity -> 3527)
对于较旧的 Scala 版本,您必须将其分解为更小的步骤。
properties.groupBy(_.name)
.map{case (k,v) => k -> v.map(_.options.map(_.price).sum).sum}
,
补充 jwvh 答案,你可以使用 cats (也在 2.12
中) 来稍微简化代码:
import cats.syntax.all._
val result = properties.foldMap {
case ProductProperty(name,_,options) =>
Map(name -> options.foldMap(_.price))
}
// result: Map[String,Quantity -> 3527)
这里的技巧是 foldMap
将 map
和 foldLeft
合并为一个步骤;所以 options.foldMap(_.price)
本质上与 options.map(_.price).foldLeft(0)(_ + _)
但是,最有趣的部分是 properties.foldMap
this 因为 Monoid
的 Maps
基本上将两个映射合并在一起,当它们具有相同的键时,它只是将其值组合在一起。
您可以看到运行 here 的代码。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。