私は移動平均などの問題を扱ういくつかの C# コードに取り組んでいます。ここでは、List / IEnumerable を取得して、連続したデータのチャンクで作業する必要があります。F# Seq モジュールには、Sequence を取り込んで、連続する要素のチャンクのシーケンスを返す、windowed という優れた関数があります。
C# には、LINQ ですぐに使用できる同等の機能がありますか?
私は移動平均などの問題を扱ういくつかの C# コードに取り組んでいます。ここでは、List / IEnumerable を取得して、連続したデータのチャンクで作業する必要があります。F# Seq モジュールには、Sequence を取り込んで、連続する要素のチャンクのシーケンスを返す、windowed という優れた関数があります。
C# には、LINQ ですぐに使用できる同等の機能がありますか?
参照するだけで、いつでもSeqModule.Windowed
C# から呼び出すことができますFSharp.Core.Dll
。関数名もわずかにマングルされているため、C# の大文字と小文字の規則に適合するように、Windowed
ではなく呼び出します。windowed
いつでも自分でロールすることができます (または 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;
}
The Reactive Extensions have a few operators to help with this, such as Buffer and Window. The Interactive Extensions, which can be found in the experimental branch, add these and a significant number of additional operators to LINQ.