Scala:产生折叠的中间结果

时间:2010-12-17 10:21:57

标签: scala functional-programming

我遇到了在整个地图操作中多次维护状态的问题。想象一下以下任务:

给定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)

但不知怎的,我觉得必须有一个更简单的解决方案。

4 个答案:

答案 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}}