Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 961
AbrahamDaniel Avatar asked Feb 03 '16 12:02

AbrahamDaniel


2 Answers

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

like image 76
PawelN Avatar answered Nov 15 '22 19:11

PawelN


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

like image 45
Alexey Romanov Avatar answered Nov 15 '22 18:11

Alexey Romanov