Esiste un equivalente alla finestra F # Seq. In C #?
Domanda
Sto lavorando su un codice C # che si occupa di problemi come le medie mobili, dove spesso ho bisogno di prendere un List / IEnumerable e lavorare su blocchi di dati consecutivi.Il modulo F # Seq ha una grande funzione, windowed, che prendendo in una sequenza, restituisce una sequenza di blocchi di elementi consecutivi.
C # ha una funzione equivalente pronta all'uso con LINQ?
Soluzione
Puoi sempre chiamare SeqModule.Windowed
da C #, devi solo fare riferimento a FSharp.Core.Dll
.Anche i nomi delle funzioni sono leggermente alterati, quindi chiami Windowed
invece di windowed
, in modo che si adatti alle convenzioni sulle maiuscole C #
Altri suggerimenti
Puoi sempre tirare il tuo (o tradurre quello dal core F #):
let windowed windowSize (source: seq<_>) =
checkNonNull "source" source
if windowSize <= 0 then invalidArg "windowSize" (SR.GetString(SR.inputMustBeNonNegative))
seq { let arr = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked windowSize
let r = ref (windowSize-1)
let i = ref 0
use e = source.GetEnumerator()
while e.MoveNext() do
arr.[!i] <- e.Current
i := (!i + 1) % windowSize
if !r = 0 then
yield Array.init windowSize (fun j -> arr.[(!i+j) % windowSize])
else
r := (!r - 1) }
Il mio tentativo è simile a questo, è molto più lento della semplice chiamata diretta di F # (come suggerito da John Palmer).Immagino che sia a causa di F # che utilizza un array Unchecked .:
public static IEnumerable<T[]> Windowed<T>(this IEnumerable<T> list, int windowSize)
{
//Checks elided
var arr = new T[windowSize];
int r = windowSize - 1, i = 0;
using(var e = list.GetEnumerator())
{
while(e.MoveNext())
{
arr[i] = e.Current;
i = (i + 1) % windowSize;
if(r == 0)
yield return ArrayInit<T>(windowSize, j => arr[(i + j) % windowSize]);
else
r = r - 1;
}
}
}
public static T[] ArrayInit<T>(int size, Func<int, T> func)
{
var output = new T[size];
for(var i = 0; i < size; i++) output[i] = func(i);
return output;
}
Le estensioni reattive hanno alcuni operatori che aiutano con Buffer e Finestra .Le estensioni interattive, che possono essere trovate nel ramo sperimentale, aggiungono queste e un numero significativo di operatori aggiuntivi a LINQ.
La risposta di John Palmer è ottima, ecco un esempio basato sulla sua risposta.
var numbers = new[] {1, 2, 3, 4, 5};
var windowed = SeqModule.Windowed(2, numbers);
Si può (o meno) aggiungere ToArray () alla fine, senza ToArray, il tipo restituito è ancora in F # world (Sequence).Con ToArray, si torna al mondo C # (Array).