Scala: What is the difference between filter and takeWhile on a stream?

12,634

Solution 1

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).

Solution 2

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

Share:
12,634
AbrahamDaniel
Author by

AbrahamDaniel

Updated on June 12, 2022

Comments

  • AbrahamDaniel
    AbrahamDaniel almost 2 years

    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.