Gibt es ein Äquivalent zum F # Seq.windowed in C #?
Frage
Ich arbeite an C # -Code, der sich mit Problemen wie gleitenden Durchschnitten befasst, bei denen ich häufig eine Liste / IEnumerable erstellen und Teile aufeinanderfolgender Daten bearbeiten muss.Das F # Seq-Modul hat eine großartige Funktion, die im Fenster angezeigt wird und eine Sequenz von Blöcken aufeinanderfolgender Elemente zurückgibt.
Verfügt C # über eine gleichwertige Funktion, die mit LINQ sofort einsatzbereit ist?
Lösung
Sie können SeqModule.Windowed
immer nur von C # aus aufrufen, Sie müssen nur auf FSharp.Core.Dll
verweisen.Die Funktionsnamen sind ebenfalls leicht entstellt, sodass Sie Windowed
anstelle von windowed
aufrufen, damit sie mit den C # -Kapitalisierungskonventionen übereinstimmen
Andere Tipps
Sie können jederzeit Ihre eigenen würfeln (oder die aus dem F # -Kern übersetzen):
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) }
Mein Versuch sieht so aus, er ist viel langsamer als nur F # direkt aufzurufen (wie von John Palmer vorgeschlagen).Ich vermute, es liegt daran, dass F # ein ungeprüftes Array verwendet:
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;
}
Die Reactive Extensions haben einige Operatoren, die dabei helfen können, wie z Puffer und Fenster .Die interaktiven Erweiterungen, die im experimentellen Zweig zu finden sind, fügen diese und eine erhebliche Anzahl zusätzlicher Operatoren zu LINQ hinzu.
John Palmer ist großartig. Hier ist ein Beispiel, das auf seiner Antwort basiert.
var numbers = new[] {1, 2, 3, 4, 5};
var windowed = SeqModule.Windowed(2, numbers);
Möglicherweise möchten Sie ToArray () am Ende hinzufügen (oder nicht). Ohne ToArray befindet sich der Rückgabetyp immer noch in der F # -Welt (Sequenz).Mit ToArray geht es zurück zu C # world (Array).