Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Summing the previous values in an IEnumerable

I have a sequence of numbers:

var seq = new List<int> { 1, 3, 12, 19, 33 };

and I want to transform that into a new sequence where the number is added to the preceding numbers to create a new sequence:

{ 1, 3, 12, 19, 33 } --> {1, 4, 16, 35, 68 }

I came up with the following, but I dislike the state variable 'count'. I also dislike the fact that I'm using the values Enumerable without acting on it.

int count = 1;
var summed = values.Select(_ => values.Take(count++).Sum());

How else could it be done?

like image 537
Ritch Melton Avatar asked Jul 01 '11 17:07

Ritch Melton


1 Answers

This is a common pattern in functional programming which in F# is called scan. It's like C#'s Enumerable.Aggregate and F#'s fold except that it yields the intermediate results of the accumulator along with the final result. We can implement scan in C# nicely with an extension method:

public static IEnumerable<U> Scan<T, U>(this IEnumerable<T> input, Func<U, T, U> next, U state) {
    yield return state;
    foreach(var item in input) {
        state = next(state, item);
        yield return state;
    }
}

And then use it as follows:

var seq = new List<int> { 1, 3, 12, 19, 33 };
var transformed = seq.Scan(((state, item) => state + item), 0).Skip(1);
like image 145
Stephen Swensen Avatar answered Oct 05 '22 16:10

Stephen Swensen