5

我有一个:

val a : Stream[Boolean] = ...

当我 foldLeft 如下

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

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

4

3 回答 3

3

它不会在第一个 true 时终止。您可以改用存在:

val b = a.exists(identity)
于 2013-01-30T19:13:10.653 回答
3

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

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

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

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)

现在递归解决方案的有趣之处在于它如何用于更一般的用例中,您实际上需要以某种方式累积值(这就是 fold 的用途)并且仍然提前终止。假设您想使用一种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)(_ + _)

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

于 2013-01-30T19:37:33.020 回答
1

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

于 2013-01-30T20:12:45.820 回答