I have an IEnumerable<IEnumerable<double>>
which can basically be thought of as a 2D array of doubles and what I want to do is get a 1D array (or list or whatever) that is the total for all the columns of my original collection. In other words, if I had:
1 2 3 4
2 3 1 6
3 4 5 6
-------------
6 9 9 16
I'd want the last line (which is not part of the original collection, obviously).
Is there a simple way to do this with LINQ so that I don't have to loop over the whole thing? I know I can use .Sum
to total one row or one column, but I want to total each row.
I've seen some other questions (mostly dealing with database queries) that suggest using group
but that didn't seem to work for me. I tried this:
var totals = from p in toTotal
group p by 1 into g
select g.Sum(t => t.First());
But that just totals everything.
Is there a clever way to do this?
Edit: for example, if toTotal
was defined as:
List<List<double>> toTotal = new List<List<double>>() {
new List<double> {1, 2, 3, 4},
new List<double> {2, 3 , 1, 6},
new List<double> {3 , 4, 5 , 6}
};
Ok. I think I've hit on it:
var totals = toTotal.Aggregate((prev, next) => prev.Zip(next, (a, b) => a + b));
The trick was that I was looking for a Fold
(or Reduce
) function, but in LINQ it's called Aggregate
.
Here's a fiddle showing this and @Habib's code for totaling rows (for comparison). The only change from what I have here (and what I was using in my actual code) is that I needed to .ToList
the result of .Zip
because for this test case I have a List<List<double>>
and that seems to upset the compiler if you don't explicitly convert to a list. In my actual code toTotal
is an IEnumerable<IEnumerable<double>>
and doesn't need converting.
EDIT:
You can do:
List<List<double>> toTotal = new List<List<double>>() {
new List<double> {1, 2, 3, 4},
new List<double> {2, 3 , 1, 6},
new List<double> {3 , 4, 5 , 6}
};
var res = toTotal.Select(r => r.Select((t, i) => new { Column = i, Value = t }))
.SelectMany(r => r)
.GroupBy(r => r.Column)
.Select(grp => new
{
Column = grp.Key,
Sum = grp.Select(r => r.Value).Sum(),
});
foreach (var item in res)
{
Console.WriteLine("Column: {0}, Sum: {1}", item.Column, item.Sum);
}
and you will get:
Column: 0, Sum: 6
Column: 1, Sum: 9
Column: 2, Sum: 9
Column: 3, Sum: 16
Old Answer
You need the Sum
for each element of your IEnumerable toTotal
you can get it like:
double[]totals = toTotal.Select(r => r.Sum()).ToArray();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With