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.
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...
See more on this question at Stackoverflow