Water Cooler v2
Water Cooler v2

Reputation: 33880

Is there a standard LINQ operator that will transform an IEnumerable<T> into another by looking ahead at its own elements

Is there a standard linq operator that will help me generate, say, an arithmetic progression out of an IEnumerable<int> without actually iterating over the elements myself?

For e.g.

int[] numbers = { 7, 12, 14, 8 };

// I would like an IEnumerable<int>
// whose values are:
IEnumerable<int> result = ... // { 19, 33, 41 }

I want to do this in a single query lazily, i.e. without having to write a foreach loop.

I am looking but can't find any combinator out of the standard ones.

I suspect I can use one of the overloads of Select coupled with Aggregate might help me do that but I am still trying it out myself and am not sure. I thought it'll be interesting to post this question and have someone else race me to it?

Update I have changed my question. The output I thought I wanted was:

{ 7 ,19, 33, 41}

Jacob answered it correctly with the code:

var accumulator = 0;
return numbers.Select(n => accumulator += n);

But I am thinking, if I wanted the output to be just

{ 19, 33, 41 }

How would I "look ahead" into the same source enumerable?

Upvotes: 0

Views: 249

Answers (2)

Lee
Lee

Reputation: 144206

This operation is usually called scan. There's no built-in operator (although F# defines it as Seq.scan but you can define it yourself:

    public static IEnumerable<TAcc> Scan<T, TAcc>(this IEnumerable<T> seq, Func<TAcc, T, TAcc> f, TAcc initial)
    {
        TAcc current = initial;
        yield return current;
        foreach(T item in seq)
        {
            current = f(current, item);
            yield return current;
        }
    }

Scan usually yields the initial value which you don't need so you can Skip it:

int[] numbers = { 7, 12, 14, 8 };
var result = numbers.Scan((acc, x) => acc + y, 0).Skip(1);

Upvotes: 2

Jacob
Jacob

Reputation: 78890

I don't know of any built-in operator to do exactly this, but it's fairly easy to implement just through a regular Select:

var accumulator = 0;
return numbers.Select(n => accumulator += n);

Upvotes: 2

Related Questions