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?

War es hilfreich?

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.

Die Antwort von

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).

 Bildbeschreibung hier eingeben

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top