I like this solution better. It generates a new sequence from the existing sequence (this means that you do not need to go through the entire sequence to get the result, which is critical if you do something like processing logs where you cannot name things like Length).
I ended up writing a blog post with more details on how I got here.
module Seq =
let grouped_by_with_leftover_processing f (f2: 'list β list <' a>) (s: seq <'a>) = let rec grouped_by_with_acc (f:' a β 'list β' list of options * 'list) acc (i.e. : IEnumerator <'a>) = seq {if ie.MoveNext () then let nextValue, leftovers = f ie.Current acc if nextValue.IsSome then gives nextValue.Value Give way! grouped_by_with_acc f residues, i.e. still let rems = f2 acc if rems.IsSome then give rems.Value} seq {Give way! grouped_by_with_acc f [] (s.GetEnumerator ())}
let YieldReversedLeftovers (f: 'list) = if f.IsEmpty then No else Some (List.rev f)
let grouped_by fs = grouped_by_with_leftover_processing f YieldReversedLeftovers s
let group_by_length_n ns = let grouping_function newValue acc = let newList = newValue :: acc // If we have the correct length, return // a Some as the first value. This will be // Get the sequence. if List.length acc = n - 1 then Some (List.rev newList), [] // If we donβt have the required length, // use None (so that it wonβt work) else None, newList
grouped_by grouping_function s
Large sequences are not a problem:
seq {for i in 1..1000000000 β i} | > Seq.group_by_length_n 3 ;; val it: seq <int list> = seq [[1; 2; 3]; [4; 5; 6]; [7; 8; nine]; [10; eleven; 12]; ...]>
James moore
source share