我遇到了在整个地图操作中多次维护状态的问题。想象一下以下任务:
给定List [Int],将每个元素映射到所有前面元素和自身的总和 因此1,2,3变为1,1 + 2,1 + 2 + 3。
我提出的一个解决方案是:
scala> val a = 1 to 5
a: scala.collection.immutable.Range.Inclusive with scala.collection.immutable.Range.ByOne = Range(1, 2, 3, 4, 5)
scala> a.foldLeft(List(0)){ case (l,i) => (l.head + i) :: l }.reverse
res3: List[Int] = List(0, 1, 3, 6, 10, 15)
但不知怎的,我觉得必须有一个更简单的解决方案。
答案 0 :(得分:31)
您正在尝试计算部分和的序列。
计算此类累积的一般操作不是fold
而是scan
,但scan
可通过fold
以您展示的方式表达(fold
实际上是scan
)生成的列表的最后一个元素。
至于Scala,我会给出example
scala> scanLeft(List(1,2,3))(0)(_ + _)
res1: List[Int] = List(0, 1, 3, 6)
答案 1 :(得分:8)
@Dario给出了答案,但只是添加scala库提供了scanLeft:
scala> List(1,2,3).scanLeft(0)(_ + _)
res26: List[Int] = List(0, 1, 3, 6)
答案 2 :(得分:7)
scan
答案是最好的答案,但值得注意的是,人们可以使折叠看起来更好和/或比您的问题更短。首先,您不需要使用模式匹配:
a.foldLeft(List(0)){ (l,i) => (l.head + i) :: l }.reverse
其次,请注意foldLeft有一个缩写:
(List(0) /: a){ (l,i) => (l.head + i) :: l }.reverse
第三,请注意,如果需要,您可以使用可以有效附加的集合,这样您就不需要反转:
(Vector(0) /: a){ (v,i) => v :+ (v.last + i) }
所以虽然这不像scanLeft
那么紧凑:
a.scanLeft(0)(_ + _)
它仍然不是太糟糕。
答案 3 :(得分:6)
我喜欢像其他人一样折叠,但FP答案更简洁,更可读:
a.map{var v=0; x=>{v+=x; v}}