Мне нравится это решение лучше. Он генерирует новую последовательность из существующей последовательности (это означает, что для получения результата не нужно проходить через всю последовательность - это важно, если вы делаете что-то вроде обработки журналов, где вы не можете вызывать такие вещи, как Length). 1001 *
Я закончил тем, что написал сообщение в блоге с более подробной информацией о том, как я попал сюда.
module Seq =
let grouped_by_with_leftover_processing f (опция f2: 'список -> список <' a>) (s: seq <'a>) =
let rec grouped_by_with_acc (f: 'a ->' список -> 'опция списка *' список) acc (т.е. IEnumerator <'a>) =
seq {
if ie.MoveNext ()
затем
let nextValue, leftovers = f ie.Current acc
если nextValue.IsSome, то привести к nextValue.Value
Уступать! grouped_by_with_acc для остатков т.е.
еще
пусть rems = f2 соотв
если rems.Ssome, то дают rems.Value
}
seq {
Уступать! grouped_by_with_acc f [] (s.GetEnumerator ())
}
let YieldReversedLeftovers (f: 'a list) =
если f.IsEmpty
тогда нет
еще некоторые (List.rev f)
let grouped_by f s =
grouped_by_with_leftover_processing f YieldReversedLeftovers s
let group_by_length_n n s =
let grouping_function newValue acc =
let newList = newValue :: acc
// Если у нас правильная длина, возвращаем
// Некоторые в качестве первого значения. Это будет
// получим по последовательности.
если List.length acc = n - 1
затем Some (List.rev newList), []
// Если у нас нет правильной длины,
// использовать None (поэтому ничего не будет получено)
еще нет, newList
grouped_by grouping_function s
Большие последовательности не являются проблемой:
seq {для i в 1..1000000000 -> i} |> Seq.group_by_length_n 3 ;;
val it: seq
= seq [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]; [10; 11; 12]; ...]
>