私はこのソリューションの方が好きです。既存のシーケンスから新しいシーケンスを生成します (つまり、結果を取得するためにシーケンス全体をトラバースする必要はありません。これは、Length などを呼び出すことができないログ処理などを行う場合に重要です)。
どうやってここにたどり着いたかについて、より詳細なブログ投稿を書くことになりました。
module Seq =
let grouped_by_with_leftover_processing f (f2: 'a list -> list<'a> オプション) (s: seq<'a>)= let rec grouped_by_with_acc (f: 'a -> 'a list -> 'a list オプション * 'a list) acc (ie: IEnumerator<'a>) = seq { if ie.MoveNext() then let nextValue, leftovers = f ie.Current acc if nextValue.IsSome then yield nextValue.Value yield! grouped_by_with_acc f 残り物 ie else let rems = f2 acc if rems.IsSome then yield rems.Value } seq { yield! grouped_by_with_acc f [] (s.GetEnumerator()) }
let YieldReversedLeftovers (f: 'a list) = if f.IsEmpty then None 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 // 正しい長さの場合、最初の値として Some を返します。それは // シーケンスによって生成されます。if List.length acc = n - 1 then Some (List.rev newList), [] // 適切な長さがない場合は // None を使用 (何も生成されない) else None, newList
grouped_by grouping_function s
大きなシーケンスは問題ではありません:
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; 9]; [10; 11; 12]; ...] >