Scala Saturday – The Stream.takeWhile Method

When you want a set number of items from the beginning of a stream, you use Stream.take. When you don’t care so much about the number, but rather the nature of the items, use Stream.takeWhile.

Stream.takeWhile starts at the beginning of the stream and applies a predicate to each item, one by one. It returns each item in a new stream until it reaches an item that does not meet the predicate:

Stream.takeWhile takes items from the beginning of a stream until it reaches an item that does not meet the given predicate.
Taking Items from a Stream While a Predicate Holds

Note that Stream.takeWhile does not return the item that fails to meet the predicate. It stops with the last item that meets the predicate.

Perhaps you have a sensor feeding you temperature readings once per minute:

import java.time.{LocalDateTime, Month}

case class Reading(
  temperature: Double, 
  timestamp: LocalDateTime)

val readings = Stream(
  Reading(89.5, 
    LocalDateTime.of(2015, Month.JULY, 19, 10, 0)),
  Reading(90.1, 
    LocalDateTime.of(2015, Month.JULY, 19, 10, 1)),
  Reading(89.9, 
    LocalDateTime.of(2015, Month.JULY, 19, 10, 2)),
  Reading(90.0, 
    LocalDateTime.of(2015, Month.JULY, 19, 10, 3)),
  Reading(90.1, 
    LocalDateTime.of(2015, Month.JULY, 19, 10, 4)),
  Reading(-1000.0, 
    LocalDateTime.of(2015, Month.JULY, 19, 10, 5)),
  Reading(-1000.0, 
    LocalDateTime.of(2015, Month.JULY, 19, 10, 6)),
  Reading(90.2, 
    LocalDateTime.of(2015, Month.JULY, 19, 10, 7))
)

Now to get all readings up until the thermometer returns the data-not-valid indicator, employ Stream.takeWhile:

val valid = readings takeWhile { _.temperature != -1000.0 }

// valid: scala.collection.immutable.Stream[Reading] = 
//   Stream(
//     Reading(89.5,2015-07-19T10:00), 
//     Reading(90.1,2015-07-19T10:01), 
//     Reading(89.9,2015-07-19T10:02), 
//     Reading(90.0,2015-07-19T10:03), 
//     Reading(90.1,2015-07-19T10:04)
//   )

Finally, Stream.takeWhile doesn’t balk if it never reaches an element that fails to meet the predicate:

val all = Stream(1,3,4,7) takeWhile { _ < 10 }
// all: scala.collection.immutable.Stream[Int] = 
//   Stream(1, 3, 4, 7)

As with Stream.take, the other collection types also define takeWhile:

One thought on “Scala Saturday – The Stream.takeWhile Method”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.