Best way to offset an enumerable with itself

Given a source IEnumerable<T> and a positive integer offset and a merge function Func<T,T,TResult> I would like to produce a new IEnumerable<TResult>

A possible signature follows:

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

Here's an example using the following inputs which will produce the offset enumerable and select the sum of the offset parts.

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));

A very important goal here is to enumerate the source IEnumerable<T> only once.

Jon Skeet
people
quotationmark

Well, it sounds like you need to buffer the results, e.g. in an array:

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;
        }
    }
}

That at least works with your example...

people

See more on this question at Stackoverflow