我正在处理一些与移动平均值等问题有关的C#代码,经常需要对连续数据块进行操作,这时我需要使用列表/List或IEnumerable。F# Seq模块有一个很好的函数windowed,它接受一个序列并返回一系列连续元素的块。
C#是否内置具有类似功能的LINQ函数?
我正在处理一些与移动平均值等问题有关的C#代码,经常需要对连续数据块进行操作,这时我需要使用列表/List或IEnumerable。F# Seq模块有一个很好的函数windowed,它接受一个序列并返回一系列连续元素的块。
C#是否内置具有类似功能的LINQ函数?
您可以随时从C#调用 SeqModule.Windowed
,您只需要引用 FSharp.Core.Dll
。函数名称也略有变化,因此您需要调用Windowed
而不是windowed
,以适应C#的大小写约定。
SeqModule.Windowed
。 - Mauricio Scheffer您可以自己编写(或翻译来自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# 使用了一个 Unchecked 数组。
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;
}
var arrR = new T[windowSize]; for (int j = 0; j < windowSize; j++) { arrR[j] = arr[(i + j) % windowSize]; }
替换对 ArrayInit
的调用,用 r--
替换 r = r - 1
。在我的测试中,它比 Seq.windowed
稍微快一点。 - DanielSeq.windowed
使用 zeroCreateUnchecked
,但它只是跳过了对 size
参数的验证(即 if size < 0 then invalidArg ...
)。它并没有避免边界检查。我相信这是由 JITer 自行决定的。 - Danielvar list = Enumerable.Range(0, 100000); var sw = Stopwatch.StartNew(); int count = list.Windowed(15).Count(); sw.Stop();
然后在一个新的范围内执行相同的操作 Microsoft.FSharp.Collections.SeqModule.Windowed
,C# 总是需要大约两倍的时间... - Benjol