5

私は持っています:

val a : Stream[Boolean] = ...

折りたたむと以下のように左へ

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

trueストリームで最初の値を見つけたときに終了しますか? そうでない場合、どうすればできますか?

4

3 に答える 3

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次のような方法で早期に「終了」するメソッドを使用して、int のストリームの値を追加したいとします||(この場合、左側が > 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 に答える
3

最初の true では終了しません。代わりに exists を使用できます。

val b = a.exists(identity)
于 2013-01-30T19:13:10.653 に答える
1

を使用して、操作したいtakeWhileのプレフィックスを抽出し、それに適用することができます。StreamfoldLeft

于 2013-01-30T20:12:45.820 に答える