I just started to learn Scala, and I'm confused between the filter and takeWhile while working on streams.
I came across this program to generate prime numbers, which uses both takeWhile and filter on a stream.
lazy val ps: Stream[Int] = 2 #:: Stream.from(3).filter(i =>
ps.takeWhile{j => j * j <= i}.forall{ k => i % k > 0});
While experimenting i found
Stream.from(1).takeWhile(_ < 10).toList
returns me
List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
while
Stream.from(1).filter(_ < 10).toList
runs infinitely.
takeWhile()
stop evaluation immediately after condition is not met.
filter
have to evaluate the whole Stream.
I suggest You to analyze this two function in below code:
https://github.com/fpinscala/fpinscala/blob/master/answers/src/main/scala/fpinscala/laziness/Stream.scala
The difference isn't stream-specific, but the same for all collections extending GenTraversableLike
:
filter
Returns all the elements that satisfy the predicate
p
takeWhile
Returns the longest prefix whose elements satisfy the predicate
p
.
E.g.
> List(1, 2, 3, 4).filter(_ % 2 == 1)
List(1, 3)
> List(1, 2, 3, 4).takeWhile(_ % 2 == 1)
List(1)
In particular, Stream.from(1).filter(_ < 10).toList
doesn't finish because it has to check every element of the stream: it doesn't "know" there won't be any elements which satisfy _ < 10
after 9 (and actually, there are, thanks to wraparound).
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