There is a good example in Stream document that gets fibonacci numbers.
val fibs:Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 }
I would like to implement that by using sliding, so I tried followings.
val test = 0 #:: 1 #:: Stream.empty
test.sliding(2).map(_.sum).toStream
Last line correctly gets Stream(1, ?) but when I concatenate that to above as follows, I get a error (possibly stack overflow, I could not see the exact error message because it was too long) when I try to get 3rd member.
val fibs2:Stream[Int] = 0 #:: 1 #:: fibs2.sliding(2).map(_.sum).toStream
If I give 3 numbers as follows, it calculates sums of preceding two numbers. But that's not fibonacci number.
val fibs3:Stream[Int] = 0 #:: 0 #:: 1 #:: fibs3.sliding(2).map(_.sum).toStream
Any ideas or help would be appreciated.
Updates
The problem seems to be that the GroupedIterator
(returned by sliding
) is over-eager. It forces the next element after your current window when creating each sliding window.
Here's a simple example:
import scala.util.Try
def bad[T]: Stream[T] = throw new RuntimeException("Don't peek!")
// Should be able to view group of first 2 elements without error,
// but sliding and grouped both read the 3rd element
def testA: Stream[Int] = 1 #:: 2 #:: bad
Try { testA.sliding(2).next }
// res0: scala.util.Try[scala.collection.immutable.Stream[Int]] = Failure(java.lang.RuntimeException: Don't peek!)
Try { testA.grouped(2).next }
// res1: scala.util.Try[scala.collection.immutable.Stream[Int]] = Failure(java.lang.RuntimeException: Don't peek!)
// Adding an extra element before the bad entry gives
// sufficient padding for a sliding window of 2
def testB: Stream[Int] = 1 #:: 2 #:: 3 #:: bad
Try { testB.sliding(2).next }
// res2: scala.util.Try[scala.collection.immutable.Stream[Int]] = Success(Stream(1, ?))
Try { testB.grouped(2).next }
// res3: scala.util.Try[scala.collection.immutable.Stream[Int]] = Success(Stream(1, ?))
Instead of sliding
, you can use scanLeft
:
val fibs: Stream[Int] = 0 #:: fibs.scanLeft(1)(_+_)
The scan
function is kind of like fold
, but produces all the intermediate results. So what you get is this:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With