Just as the analog to Stream.take
is Stream.skip
, the analog to Stream.takeWhile
is Stream.dropWhile
. That is, when you don’t care so much about dropping a certain number of items, but rather a certain kind of items.
Stream.dropWhile
starts at the beginning of the stream and applies a predicate to each item, one by one. It does not start returning items in a new stream until it reaches an item that does not meet the predicate. Then it stops checking elements against the predicate and returns every item in the stream from that point on:
Assume you have the same temperature sensor as the one in my post on Stream.takeWhile
. This time, instead of once per minute, assume that it feeds you temperature readings once per second. Add to that the idea that the sensor has a few seconds of boot-up time in which it sends you -1000.0—the indication that the current reading is invalid—until it has fully booted and can start sending good temperature data.
import java.time.{LocalDateTime, Month} case class Reading(temperature: Double, timestamp: LocalDateTime) val readings = Stream( Reading(-1000.0, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 0)), Reading(-1000.0, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 1)), Reading(-1000.0, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 2)), Reading(-1000.0, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 3)), Reading(-1000.0, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 4)), Reading(-1000.0, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 5)), Reading(90.1, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 6)), Reading(90.2, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 7)), Reading(90.2, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 8)), Reading(90.3, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 9)), Reading(90.2, LocalDateTime.of(2015, Month.JULY, 19, 10, 0, 10)) )
To drop all readings until the thermometer starts returning valid data, use Stream.dropWhile
:
val valid = readings dropWhile (_.temperature == -1000.0) // valid: scala.collection.immutable.Stream[Reading] = // Stream(Reading(90.1,2015-07-19T10:00:06), // Reading(90.2,2015-07-19T10:00:07), // Reading(90.2,2015-07-19T10:00:08), // Reading(90.3,2015-07-19T10:00:09), // Reading(90.2,2015-07-19T10:00:10))
Finally, like Stream.takeWhile
, Stream.dropWhile
doesn’t balk if it never reaches an element that fails to meet the predicate. You just get an empty stream:
val none = Stream(1,3,4,7) dropWhile { _ < 10 } // none: scala.collection.immutable.Stream[Int] = Stream()