Just as the analog to Seq.take
is Seq.skip
, the analog to Seq.takeWhile
is Seq.skipWhile
. That is, when you don’t care so much about skipping a certain number of items, but rather a certain kind of items.
Seq.skipWhile
starts at the beginning of the sequence and applies a predicate to each item, one by one. It does not start returning items in a new sequence 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 sequence from that point on:
Assume you have the same temperature sensor as the one in my post on Seq.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.
type Reading = { Temperature : float Timestamp : DateTime } let readings = seq [ { Temperature = -1000.0 Timestamp = DateTime(2015, 07, 19, 10, 0, 0) } { Temperature = -1000.0 Timestamp = DateTime(2015, 07, 19, 10, 0, 1) } { Temperature = -1000.0 Timestamp = DateTime(2015, 07, 19, 10, 0, 2) } { Temperature = -1000.0 Timestamp = DateTime(2015, 07, 19, 10, 0, 3) } { Temperature = -1000.0 Timestamp = DateTime(2015, 07, 19, 10, 0, 4) } { Temperature = -1000.0 Timestamp = DateTime(2015, 07, 19, 10, 0, 5) } { Temperature = 90.1 Timestamp = DateTime(2015, 07, 19, 10, 0, 6) } { Temperature = 90.2 Timestamp = DateTime(2015, 07, 19, 10, 0, 7) } { Temperature = 90.2 Timestamp = DateTime(2015, 07, 19, 10, 0, 8) } { Temperature = 90.1 Timestamp = DateTime(2015, 07, 19, 10, 0, 9) } { Temperature = 90.3 Timestamp = DateTime(2015, 07, 19, 10, 0, 10) } ]
To skip all readings until the thermometer starts returning valid data, use Seq.skipWhile
:
let valid = readings |> Seq.skipWhile (fun r -> r.Temperature = -1000.0) // val valid: seq<Reading> = // [{Temperature = 90.1; // Timestamp = 7/19/2015 10:00:06 AM}; // {Temperature = 90.2; // Timestamp = 7/19/2015 10:00:07 AM}; // {Temperature = 90.2; // Timestamp = 7/19/2015 10:00:08 AM}; // {Temperature = 90.1; // Timestamp = 7/19/2015 10:00:09 AM}; // {Temperature = 90.3; // Timestamp = 7/19/2015 10:00:10 AM}]
Finally, even though Seq.skip
throws an exception if you ask it to skip more elements than the sequence contains, Seq.skipWhile
does not balk if it never reaches an element that fails to meet the predicate. You just get an empty sequence:
let none = seq [1;3;4;7] |> Seq.skipWhile (fun n -> n < 10) // val none : seq<int> = seq []
As of F# 4.0, there are versions of skipWhile
in the Array
and List
modules, but as of this writing, the documentation at MSDN does not yet include them.
One reply on “F# Friday – The Seq.skipWhile Function”
[…] F# Friday – The Seq.skipWhile Function – Brad Collins […]