2012-01-16 78 views
6

我正在處理一些C#代碼,這些代碼處理移動平均數等問題,我經常需要使用List/IEnumerable並處理連續數據塊。 F#Seq模塊有一個很好的功能,窗口化,它接受一個序列,返回一系列連續元素的序列。是否有與C#中的F#Seq.windowed相當的功能?

C#是否具有LINQ的開箱即用功能?

+0

提供已接受答案的用戶承認這是錯誤的,您現在可能需要考慮選擇另一個答案。 – Kev 2012-01-17 00:01:16

回答

5

你可以隨時從C#調用SeqModule.Windowed,你只需要參考FSharp.Core.Dll。該功能的名稱也略有錯位,所以你打電話Windowed而非windowed,使其與C#的大小寫約定適合

+0

在這裏,在這裏,一直這樣做! Seq.singleton,FSharpSet,你的名字。當我必須用C#編寫代碼時,我經常使用F#stdlib。沒有它我怎麼能活下去! – kkm 2012-01-16 04:45:20

+1

實際上它是'SeqModule.Windowed'。 – 2012-01-16 13:30:03

2

你總是可以推出自己的(或翻譯從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) } 

我的嘗試看起來像這樣,它比直接調用F#要慢(正如John Palmer所建議的)。我使用的是未經檢查的數組:

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

用'var arrR = new T [windowSize];將調用替換爲'ArrayInit'; for(int j = 0; j Daniel 2012-01-16 15:37:53

+1

'Seq.windowed'使用'zeroCreateUnchecked',但它只是跳過'size'參數的驗證(即如果size <0 then invalidArg ...')。它不避免邊界檢查。我相信這是由JITer自行決定的。 – Daniel 2012-01-16 15:44:43

+0

@丹尼爾,很高興看到有人拿着誘餌:)我不能得到你的結果。如果我做'var list = Enumerable.Range(0,100000); var sw = Stopwatch.StartNew(); int count = list.Windowed(15).Count(); sw.Stop();'然後'Microsoft.FSharp.Collections.SeqModule.Windowed'(在一個新的範圍),同樣的事情,C#總是需要大約兩倍長... – Benjol 2012-01-17 05:46:29

1

Reactive Extensions有幾個運營商來解決這個問題,比如BufferWindow猜測這是因爲F#。可以在實驗分支中找到交互式擴展,將這些和大量額外的運算符添加到LINQ中。

相關問題