我有一个班级:
case class Custom(label: String, num: Long)
鉴于这两个清单:
val l1 = Vector(Custom("a", 1), Custom("aa", 1))
val l2 = Vector(Custom("a", 1))
我希望获得结果列表:
val l3 = Vector(Custom("a", 2), Custom("aa", 1))
我试过像这样使用折叠:
l1.foldLeft(l2)((acc: List[Custom], el: Custom) => {
val itemWithIndex: Option[(Custom, Int)] = acc.zipWithIndex.find(_._1.label == el.label)
itemWithIndex match {
case Some(x) => acc.updated(x._2, Custom(el.label, acc(x._2).num + el.num))
case None => el :: acc
}
})
此实现迭代累加器(l2
)3次,l1
迭代一次。我正在寻找更有效的解决方案。
答案 0 :(得分:2)
布莱恩提出了一个很好的建议,就是简单地将这些列表合并到一起:
(l1 ++ l2)
.groupBy(_.label)
.map {
case (label, customs) => Custom(label, customs.map(_.num).sum)
}
groupBy
为我们提供了Map[String, List[Custom]]
,其中List[Custom]
是具有相同标签的所有Custom
个对象。剩下的就是总结List
,并为每个标签创建一个新的Custom
对象。
由于这是一个减少,它可以被制成一个Monoid:
implicit def customMonoid = new Monoid[Vector[Custom]] {
override def append(l1: Vector[Custom], l2: => Vector[Custom]): Vector[Custom] =
(l1 ++ l2)
.groupBy(_.label)
.map {
case (a, b) => Custom(a, b.map(_.num).sum)
}.toVector
override def zero: Vector[Custom] = Vector.empty[Custom]
}
答案 1 :(得分:1)
import scalaz.syntax.monoid._
case class Custom(label: String, num: Long)
val l1 = Vector(Custom("a", 1), Custom("aa", 1))
val l2 = Vector(Custom("a", 1))
def toM(v: Vector[Custom]): Map[String, Long] = {
(v map (cus ⇒ cus.label → cus.num)).toMap
}
def fromM(m: Map[String, Long]): Vector[Custom] = {
m.map{case (l , num) ⇒ Custom(l, num)}.toVector
}
implicit val myMonoid = new Monoid[Vector[Custom]] {
import scalaz.std.anyVal.longInstance
val mm = scalaz.std.map.mapMonoid[String, Long]
override def zero: Vector[Custom] = fromM(mm.zero)
override def append(f1: Vector[Custom], f2: ⇒ Vector[Custom]): Vector[Custom] = fromM(mm.append(toM(f1), toM(f2)))
}
println(l1 |+| l2) \\Vector(Custom(a,2), Custom(aa,1))
如果您想更清楚,可以将toM
和fromM
提取到Isomorphism实例。