¿Existe un equivalente a la ventana F # Seq. En C #?
Pregunta
Estoy trabajando en un código C # que se ocupa de problemas como promedios móviles, donde a menudo necesito tomar una Lista / IEnumerable y trabajar en fragmentos de datos consecutivos.El módulo F # Seq tiene una gran función, en ventana, que tomando una secuencia, devuelve una secuencia de fragmentos de elementos consecutivos.
¿C # tiene una función equivalente lista para usar con LINQ?
Solución
Siempre puede llamar a SeqModule.Windowed
desde C #, solo necesita hacer referencia a FSharp.Core.Dll
.Los nombres de las funciones también están ligeramente alterados, por lo que se llama Windowed
en lugar de windowed
, de modo que se ajuste a las convenciones de uso de mayúsculas de C #
Otros consejos
Siempre puede lanzar el suyo (o traducir el del núcleo de 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) }
Mi intento se ve así, es mucho más lento que simplemente llamar a F # directamente (como sugirió John Palmer).Supongo que se debe a que F # usa una matriz sin marcar .:
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;
}
Las Reactive Extensions tienen algunos operadores para ayudar con esto, como Búfer y Ventana .Las extensiones interactivas, que se pueden encontrar en la rama experimental, agregan estos y un número significativo de operadores adicionales a LINQ.
La respuesta de John Palmer es excelente, aquí hay un ejemplo basado en su respuesta.
var numbers = new[] {1, 2, 3, 4, 5};
var windowed = SeqModule.Windowed(2, numbers);
Puede (o no) querer agregar ToArray () al final, sin ToArray, el tipo de retorno todavía está en el mundo F # (Sequence).Con ToArray, vuelve al mundo C # (Array).