递归很酷,但是当你被更高阶的库函数包围时,它的级别很低。我试图避免为依赖于最后生成的值的进程编写递归函数。
我通常会在Clojure中使用iterate
函数而不是最后一个值和当前参数的“压缩”列表。 Scala的集合API中是否存在等效函数?
这是在一些疯狂的伪代码中尝试抽象的例子:
说你有
Seq(1,2,3)
您对生成的最后一个值以及列表中的下一个项执行了一些操作:
lastValue ^ 2 + nextInt(i)
并且您希望累积生成的所有值。
我正在努力避免写一些类似的东西:
def f(ls:Seq[Int]):Seq[Float] = {
def g(pos:Int, lastGen:Float):Seq[Float] = {
val v = gen(lastGen, ls(pos))
if( end(v) )
Seq(v)
else
Seq(v) ++ g(pos+1, v)
}
f(0, 1)
}
我在Haskell中定义了一个类似于偏移流版本的Fibonacci的东西,所以假设我可以使用一个引用自己的懒惰流,但是这比Clojure的迭代更难包裹我的大脑。
答案 0 :(得分:6)
这是你要找的吗?它与Clojure中的iterate
基本相同:
List.iterate(1, 5) { _ + 1 }
// res1: List[Int] = List(1, 2, 3, 4, 5)
我认为iterate
List
的定义来自GenTraversableFactory
。
唯一的缺点是第二个参数len
是你想要的参数数量,因此它不会像Clojure中那样返回iterate
之类的无限序列。
的更新强> 的
刚学到新东西! Stream
对象也有一个iterate
方法,这可以让你创建无限的懒惰流:
(Stream.iterate(1) { _ * 2 } take 5).toList
// res1: List[Int] = List(1, 2, 4, 8, 16)
答案 1 :(得分:3)
您展示的代码基本上等同于:
ls.foldLeft(List(1.0))((a, b) => gen(a.head, b) :: a).reverse
答案 2 :(得分:0)
听起来你想要的高阶函数是scanLeft
,它就像一个记住其中间步骤的折叠。例如,假设您有以下内容:
val ls = Seq(1, 2, 3)
def gen(lastValue: Double, n: Int) = math.pow(lastValue, 2) + n
然后你可以将它们与scanLeft
:
scala> ls.scanLeft(1.0)(gen)
res0: Seq[Double] = List(1.0, 2.0, 6.0, 39.0)
这或多或少等同于Apocalisp使用foldLeft
的公式,除了scanLeft
负责保留中间值。