微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Scala从列表转换为具有求和逻辑的属性映射

如何解决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)

这里的技巧是 foldMapmapfoldLeft 合并为一个步骤;所以 options.foldMap(_.price) 本质上与 options.map(_.price).foldLeft(0)(_ + _)

相同

但是,最有趣的部分是 properties.foldMap this 因为 MonoidMaps 基本上将两个映射合并在一起,当它们具有相同的键时,它只是将其值组合在一起。


您可以看到运行 here 的代码。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。