2012-01-16 82 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中。

相关问题