是否有相当于C#中的F#Seq.windowed?

时间:2012-01-16 01:25:22

标签: c# linq f# windowed

我正在研究一些处理移动平均线等问题的C#代码,我经常需要使用List / IEnumerable并处理连续数据块。 F#Seq模块具有很好的功能,窗口化,它接收序列,返回一系列连续元素的序列。

C#是否具有与LINQ开箱即用的等效功能?

4 个答案:

答案 0 :(得分:7)

您始终可以从C#拨打SeqModule.Windowed,只需要参考FSharp.Core.Dll即可。函数名称也略有损坏,因此您调用Windowed而不是windowed,以便它符合C#大写约定

答案 1 :(得分: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建议的那样)。我猜这是因为F#使用了一个未经检查的数组:

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

答案 2 :(得分:1)

Reactive Extensions有一些运营商可以帮助解决此问题,例如BufferWindow。可以在实验分支中找到的Interactive Extensions将这些以及大量额外的运算符添加到LINQ。

答案 3 :(得分:0)

John Palmer的答案很好,这是基于他的答案的示例。

var numbers = new[] {1, 2, 3, 4, 5}; 
var windowed = SeqModule.Windowed(2, numbers);

您可能(或不希望)将ToArray()添加到末尾,而没有ToArray,返回类型仍然在F#世界中(序列)。使用ToArray,它又回到了C#世界(数组)。

enter image description here