foldLeft在Stream [布尔]中提前终止?

时间:2013-01-30 19:04:53

标签: scala

我有一个:

val a : Stream[Boolean] = ...

当我将它折叠时,如下所示

val b = a.foldLeft(false)(_||_)

它会在流中找到第一个true值时终止吗?如果没有,我该如何做到?

3 个答案:

答案 0 :(得分:3)

不,它不会提前终止。这很容易说明:

val a : Stream[Boolean] = Stream.continually(true)
// won't terminate because the strea
val b = a.foldLeft(false)(_||_)

stew表明,在您的具体情况下,提前终止的简单解决方案是

val b = a.exists(identity).

更简单,这相当于:

val b = a.contains(true)

与上述不同的更通用的解决方案也适用,如果你真的需要折叠,是使用递归(请注意,这里我假设流是非空的,为简单起见):

def myReduce( s: Stream[Boolean] ): Boolean = s.head || myReduce( s.tail )
val b = myReduce(a)

现在,递归解决方案的有趣之处在于如何在一个更通用的用例中使用它,你实际上需要以某种方式累积值(这是折叠的用途)并且仍然提前终止< / em>的。假设您要使用add方法添加整数流的值,该方法将以类似于||的方式提前“终止”(在这种情况下,它不会评估其右侧)如果左侧是> 100):

def add(x: Int, y: => Int) = if ( x >= 100 ) x else x + y
val a : Stream[Int] = Stream.range(0, Int.MaxValue)
val b = a.foldLeft(0)(add(_, _))

最后一行不会终止,就像你的例子一样。但你可以像这样解决它:

def myReduce( s: Stream[Int] ): Int = add( s.head, myReduce( s.tail ) )
val b = myReduce(a)

警告:这种方法有一个明显的缺点:myReduce这里不是尾递归,这意味着如果迭代过多的流元素,它会破坏你的堆栈。 还有另一种解决方案就是这样做:

val b = a.takeWhile(_ <= 100).foldLeft(0)(_ + _)

但我担心我在非主题方面走得太远,所以我现在最好停下来。

答案 1 :(得分:2)

它不会在第一个真实时终止。您可以改为使用exists:

val b = a.exists(identity)

答案 2 :(得分:1)

您可以使用takeWhile提取您要操作的Stream的前缀,然后将foldLeft应用于此。