Another module function new with F# 4.0 is Seq.chunkBySize (so new, in fact, that there is not even a hint of it on MSDN as of this writing, and hence the Github link). Seq.chunkBySize groups a sequence’s elements into arrays (chunks) of a given size.
To take an example, if you have a sequence of twelve elements and call Seq.chunkBySize to turn it into groups of three, you’ll get a sequence of four arrays, each three elements in size:
let xs = seq [1..12] let chunked = xs |> Seq.chunkBySize 3 // val chunked : seq<int []> = // seq [[|1; 2; 3|]; [|4; 5; 6|]; // [|7; 8; 9|]; [|10; 11; 12|]]
What happens if you use a chunk size that does not divide evenly into the size of your input sequence? No sweat! The last array just contains any remaining elements, however many they may be:
let xs = seq [1..10] let chunked = xs |> Seq.chunkBySize 3 // val chunked : seq<int []> = // seq [[|1; 2; 3|]; [|4; 5; 6|]; // [|7; 8; 9|]; [|10|]]
Where is this useful? Well, you can take my paging example from my F# Friday post on Seq.skip and make it slightly clearer without the (page - 1) * perPage arithmetic:
type Book =
{ Title : string
Author : string }
let books =
seq [
{ Title = "Wuthering Heights"
Author = "Emily Bronte" }
{ Title = "Jane Eyre"
Author = "Charlotte Bronte" }
{ Title = "Agnes Grey"
Author = "Anne Bronte" }
{ Title = "The Scarlet Letter"
Author = "Nathaniel Hawthorne" }
{ Title = "Silas Marner"
Author = "George Eliot" }
{ Title = "1984"
Author = "George Orwell" }
{ Title = "Billy Budd"
Author = "Herman Melville" }
{ Title = "Moby Dick"
Author = "Herman Melville" }
{ Title = "The Great Gatsby"
Author = "F. Scott Fitzgerald" }
{ Title = "Tom Sawyer"
Author = "Mark Twain" }
]
let perPage = 3
let page = 3
let records =
books
|> Seq.chunkBySize perPage
|> Seq.skip (page - 1)
|> Seq.head
// val records : Book [] =
// [|{Title = "Billy Budd";
// Author = "Herman Melville";};
// {Title = "Moby Dick";
// Author = "Herman Melville";};
// {Title = "The Great Gatsby";
// Author = "F. Scott Fitzgerald";}|]
This time, instead of having to calculate the number of elements to skip in order to skip n pages, you first use Seq.chunkBySize to turn the sequence into a paged recordset; each “page” is n records long. Then skip page - 1 pages in order to get to the page of records you want. Finally, calling Seq.head is necessary because, remember, Seq.chunkBySize turns a flat sequence into a sequence of arrays.
One final note: the Array and List modules also contain a chunkBySize function in F# 4.0.
One reply on “F# Friday – The Seq.chunkBySize Function”
[…] F# Friday – The Seq.chunkBySize Function – Brad Collins […]