Categories

F# Friday – The Seq.takeWhile Function

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

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

Note that Seq.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:

Temperature : float
Timestamp : DateTime
}

seq [
{ Temperature = 89.5
Timestamp = DateTime(2015, 07, 19, 10, 0, 0) }
{ Temperature = 90.1
Timestamp = DateTime(2015, 07, 19, 10, 1, 0) }
{ Temperature = 89.9
Timestamp = DateTime(2015, 07, 19, 10, 2, 0) }
{ Temperature = 90.0
Timestamp = DateTime(2015, 07, 19, 10, 3, 0) }
{ Temperature = 90.1
Timestamp = DateTime(2015, 07, 19, 10, 4, 0) }
{ Temperature = -1000.0
Timestamp = DateTime(2015, 07, 19, 10, 5, 0) }
{ Temperature = -1000.0
Timestamp = DateTime(2015, 07, 19, 10, 6, 0) }
{ Temperature = 90.2
Timestamp = DateTime(2015, 07, 19, 10, 7, 0) }
]

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

let valid =
|> Seq.takeWhile (fun r -> r.Temperature <> -1000.0)

//   [{Temperature = 89.5;
//     Timestamp = 7/19/2015 10:00:00 AM};
//    {Temperature = 90.1;
//     Timestamp = 7/19/2015 10:01:00 AM};
//    {Temperature = 89.9;
//     Timestamp = 7/19/2015 10:02:00 AM};
//    {Temperature = 90.0;
//     Timestamp = 7/19/2015 10:03:00 AM};
//    {Temperature = 90.1;
//     Timestamp = 7/19/2015 10:04:00 AM}]

Finally, even though Seq.take throws an exception if you ask it for more elements than it can provide, Seq.takeWhile does not balk if it never reaches an element that fails to meet the predicate:

let all = seq [1;3;4;7]
|> Seq.takeWhile (fun n -> n < 10)
// val all : seq<int> [1; 3; 4; 7]

As of F# 4.0, there are versions of takeWhile in the Array and List modules, but as of this writing, the documentation on MSDN does not yet include them.

2 replies on “F# Friday – The Seq.takeWhile Function”

[…] F# Friday â€“ The Seq.takeWhile Function –Â Brad Collins […]

[…] 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 […]

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