Есть ли эквивалент C # Seq.windowed в C #? - PullRequest
6 голосов
/ 16 января 2012

Я работаю над некоторым кодом C #, имеющим дело с такими проблемами, как скользящие средние, где мне часто приходится брать List / IEnumerable и работать с кусками последовательных данных.Модуль F # Seq имеет замечательную оконную функцию, которая принимает последовательность и возвращает последовательность фрагментов последовательных элементов.

Имеет ли C # эквивалентную встроенную функцию с LINQ?

Ответы [ 4 ]

7 голосов
/ 16 января 2012

Вы всегда можете просто позвонить SeqModule.Windowed из C #, вам просто нужно сослаться на FSharp.Core.Dll.Имена функций также немного искажены, поэтому вы вызываете Windowed, а не windowed, чтобы соответствовать соглашениям об использовании заглавных букв в C #

2 голосов
/ 16 января 2012

Вы всегда можете свернуть свой собственный (или перевести один из ядра 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 # напрямую (как предложил Джон Палмер). Я предполагаю, что это из-за того, что 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;
}
1 голос
/ 16 января 2012

У Reactive Extensions есть несколько операторов, чтобы помочь с этим, таких как Buffer и Window . Интерактивные расширения, которые можно найти в экспериментальной ветке, добавляют эти и значительное количество дополнительных операторов к LINQ.

0 голосов
/ 09 июля 2018

John Palmer ответ отличный, вот пример, основанный на его ответе.

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

Вы можете (или нет) хотеть добавить ToArray () до конца, без ToArray, тип возвращаемого значения все еще в мире F # (Sequence). С ToArray он возвращается в мир C # (Array).

enter image description here

...