用自身抵消可枚举的最佳方法

时间:2014-07-09 16:32:20

标签: c# linq

给定源IEnumerable<T>和正整数偏移量以及合并函数Func<T,T,TResult>我想生成一个新的IEnumerable<TResult>

可能的签名如下:

public static IEnumerable<TResult> Offset<T, TResult>(
    this IEnumerable<T> source, int offset, Func<T,T,TResult> selector
);

这是一个使用以下输入的示例,它将产生可枚举的偏移量并选择偏移部分的总和。

typeof(T) = typeof(int);
typeof(TResult) = typeof(int);
source = Enumerable.Range(0, 10);
offset = 1;
selector = (original, offsetValue) => original + offsetValue;

result = source.Offset(offset, selector);

expected = new int[]{1,3,5,7,9,11,13,15,17};
Assert.IsTrue(expected.SequenceEquals(result));

此处一个非常重要的目标是仅枚举来源IEnumerable<T>

2 个答案:

答案 0 :(得分:2)

您需要跟踪以前的offset项目。 Queue可能是执行此操作的最有效工具。如果所述队列中有足够的项目,则将当前项目与出队项目配对并生成它。

public static IEnumerable<TResult> Offset<T, TResult>(
    this IEnumerable<T> source, int offset, Func<T, T, TResult> selector)
{
    var queue = new Queue<T>(offset);
    foreach (var item in source)
    {
        if (queue.Count >= offset)
            yield return selector(queue.Dequeue(), item);

        queue.Enqueue(item);
    }
}

答案 1 :(得分:1)

嗯,听起来你需要缓冲结果,例如在数组中:

public static IEnumerable<TResult> Offset<T, TResult>(
    this IEnumerable<T> source, int offset, Func<T,T,TResult> selector)
{
    // TODO: Shenanigans to validate arguments eagerly

    T[] buffer = new T[offset];
    using (var iterator = source.GetEnumerator())
    {
        for (int i = 0; i < offset && iterator.MoveNext(); i++)
        {
            buffer[i] = iterator.Current;
        }

        int index = 0;
        while (iterator.MoveNext())
        {
            T old = buffer[index];
            T current = iterator.Current;
            yield return selector(old, current);
            buffer[index] = current;
            index = (index + 1) % offset;
        }
    }
}

这至少适用于你的例子......