Ich bin gefallen, diese Lösung besser. Es erzeugt eine neue Sequenz aus der bestehenden Sequenz (das heißt, es muss nicht die gesamte Sequenz durchlaufen, um ein Ergebnis zu erhalten - das ist wichtig, wenn Sie etwas wie die Protokollverarbeitung tun, wo Sie Dinge wie Länge nicht nennen können).
Ich schrieb ein blog post mit mehr Details darüber, wie ich hierher kam.
module Seq =
lassen grouped_by_with_leftover_processing f (f2: 'eine Liste -> Liste <' a> Option) (s: seq < 'a>) = rec grouped_by_with_acc (f lassen:' a -> ‚eine Liste - > 'eine Liste Option *' eine Liste) acc (dh: IEnumerator < ‚a>) = seq { wenn ie.MoveNext() dann nextvalue, Reste = f ie.Current nach wenn nextValue.IsSome dann lassen Ausbeute nextValue.Wert Ausbeute! grouped_by_with_acc f Reste dh sonst rem = f2 lassen nach wenn rems.IsSome dann rems.Value ergeben} seq { Ausbeute! grouped_by_with_acc f [] (s.GetEnumerator()) }
lassen YieldReversedLeftovers (f: ‚a list) = wenn f.IsEmpty dann keine sonst Einige (List.rev f)
let grouped_by fs = grouped_by_with_leftover_processing f YieldReversedLeftovers s
lassen group_by_length_n ns = grouping_function newValue acc lassen = lassen newList = newValue :: acc // Wenn wir die richtige Länge haben, kehren // a Einige als erster Wert. Das wird // durch die Sequenz ergeben. wenn List.length acc = n - 1 dann keine Einige (List.rev newList), [] // Wenn wir nicht die richtige Länge haben // Keine verwenden (so wird nichts nachgegeben werden) sonst newList,
grouped_by grouping_function s
Große Sequenzen sind kein Problem:
seq {für i in 1..1000000000 - > i} | > Seq.group_by_length_n 3 ;; val it: seq < int Liste > = seq [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]; [10; 11; 12]; ...] >
Große Antwort. Ich war dem mit meinem Code nahe, hatte es aber nicht ganz. – gradbot