KVB ответ может не дать вам то, что вы хотите. Seq.windowed
возвращает скользящее окно значений , например, [1; 2; 3; 4]
становится [[1; 2; 3]; [2; 3; 4]]
. Кажется, что вы хотите, чтобы это раскололось на смежные куски. Следующая функция берет список и возвращает список троек ('T list -> ('T * 'T * 'T) list
).
let toTriples list =
let rec aux f = function
| a :: b :: c :: rest -> aux (fun acc -> f ((a, b, c) :: acc)) rest
| _ -> f []
aux id list
Вот обратное:
let ofTriples triples =
let rec aux f = function
| (a, b, c) :: rest -> aux (fun acc -> f (a :: b :: c :: acc)) rest
| [] -> f []
aux id triples
EDIT
Если вы имеете дело с огромными объемами данных, вот основанный на последовательности подход с постоянным использованием памяти (все создаваемые им option
s и tuple
s оказывают негативное влияние на GC - см. ниже для лучшей версии):
let (|Next|_|) (e:IEnumerator<_>) =
if e.MoveNext() then Some e.Current
else None
let (|Triple|_|) = function
| Next a & Next b & Next c -> Some (a, b, c) //change to [|a;b;c|] if you like
| _ -> None
let toSeqTriples (items:seq<_>) =
use e = items.GetEnumerator()
let rec loop() =
seq {
match e with
| Triple (a, b, c) ->
yield a, b, c
yield! loop()
| _ -> ()
}
loop()
РЕДАКТИРОВАТЬ 2
Вопрос Эбба об использовании памяти побудил меня протестировать, и я обнаружил, что toSeqTriples
медленный и вызывает удивительно частые GC. Следующая версия устраняет эти проблемы и почти в 4 раза быстрее, чем версия на основе списка.
let toSeqTriplesFast (items:seq<_>) =
use e = items.GetEnumerator()
let rec loop() =
seq {
if e.MoveNext() then
let a = e.Current
if e.MoveNext() then
let b = e.Current
if e.MoveNext() then
let c = e.Current
yield (a, b, c)
yield! loop()
}
loop()
Это имеет относительно постоянное использование памяти по сравнению со списком или подходом на основе массива, потому что a) если у вас есть seq
, чтобы начать со всей последовательности, не нужно впадать в список / массив; и б) он также возвращает последовательность, делая ее ленивой и избегая выделения еще одного списка / массива.