2012-01-16 18 views
6

Pracuję nad jakimś kodem C#, który zajmuje się problemami, takimi jak średnie kroczące, gdzie często potrzebuję wykonać listę/IEnumerable i pracować nad fragmentami kolejnych danych. Moduł F # Seq ma świetną funkcję, okienkową, która przechwytując sekwencję zwraca sekwencję fragmentów kolejnych elementów.Czy istnieje odpowiednik F # Seq.windowed w C#?

Czy C# ma równoważną funkcję po uruchomieniu z LINQ?

+0

Użytkownik, który dostarczył zaakceptowaną odpowiedź, przyznał, że jest źle, możesz rozważyć wybór innego teraz. – Kev

Odpowiedz

5

Zawsze możesz po prostu zadzwonić pod numer SeqModule.Windowed z C#, wystarczy odwołać się do FSharp.Core.Dll. Nazwy funkcji są również nieco zniekształcone, więc zadzwonić Windowed zamiast windowed tak, że pasuje do konwencji kapitalizacji C#

+0

Tutaj, robiąc to przez cały czas! Seq.singleton, FSharpSet, ty to nazwij. Kiedy muszę kodować w C#, często przychodzę do używania F # stdlib. Jak mogłem żyć bez tego! – kkm

+1

To właściwie "SeqModule.Windowed". –

2

Można zawsze toczyć własne (lub przetłumaczyć jedną z F # rdzenia):

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

Moja próba wygląda tak, jest wolniejsza niż zwykłe wywoływanie F # bezpośrednio (jak sugeruje John Palmer). Zgaduję, że to z powodu F # przy użyciu niezaznaczone tablicę .:

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; 
} 
+0

Zamień wywołanie na 'ArrayInit' z' var arrR = new T [windowSize]; for (int j = 0; j Daniel

+1

'Seq.windowed' używa' zeroCreateUnchecked', ale po prostu pomija walidację parametru 'size' (to znaczy' if size <0 then invalidArg ... '). Nie zapobiega to sprawdzaniu granic. Zdaje mi się, że dzieje się to według uznania JITer. – Daniel

+0

@Daniel, miło widzieć, że ktoś wziął przynętę :) Nie mogę jednak uzyskać twoich wyników. Jeśli wykonuję 'var list = Enumerable.Range (0, 100000); var sw = Stopwatch.StartNew(); int count = list.Windowed (15) .Count(); sw.Stop(); 'a następnie to samo z' Microsoft.FSharp.Collections.SeqModule.Windowed' (w nowym zakresie), C# zawsze zajmuje mniej więcej dwa razy więcej ... – Benjol

1

Reactive Extensions mieć kilku operatorów w tym pomóc, takie jak Buffer i Window. Interaktywne rozszerzenia, które można znaleźć w gałęzi eksperymentalnej, dodają te i znaczną liczbę dodatkowych operatorów do LINQ.