我有一个IEnumerable<IEnumerable<double>>
,它基本上可以被认为是一个双精度的2D数组,我想做的是得到一个1D数组(或列表或其他什么),它是我原始集合中所有列的总和。换句话说,如果我有:
1 2 3 4
2 3 1 6
3 4 5 6
-------------
6 9 9 16
我想要最后一行(显然这不是原始收藏的一部分)。
有没有一种简单的方法可以用LINQ做到这一点,这样我就不必循环整个事情了?我知道我可以使用.Sum
来合计一行或一列,但我想合计每一行。
我看到一些其他问题(主要是关于数据库查询)建议使用group
,但这似乎对我不起作用
var totals = from p in toTotal
group p by 1 into g
select g.Sum(t => t.First());
但这只是一切的总和。
有什么聪明的方法可以做到这一点吗?
编辑:例如,如果toTotal
定义为:
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 totals = toTotal.Aggregate((prev, next) => prev.Zip(next, (a, b) => a + b));
诀窍是我在寻找一个Fold
(或Reduce
)函数,但在LINQ中它被称为Aggregate
。
这里有一个小提琴展示了这一点和@Habib的代码,用于合计行数(用于比较)。与这里的内容(以及我在实际代码中使用的内容)相比,唯一的变化是我需要.ToList
.Zip
的结果,因为对于这个测试用例,我有一个List<List<double>>
,如果你不显式转换为列表,这似乎会让编译器感到不安。在我的实际代码中,toTotal
是一个IEnumerable<IEnumerable<double>>
,不需要转换。
编辑:
你可以做:
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);
}
你会得到:
Column: 0, Sum: 6
Column: 1, Sum: 9
Column: 2, Sum: 9
Column: 3, Sum: 16
旧答案
对于IEnumerable toTotal
的每个元素,您都需要Sum
,您可以获得以下内容:
double[]totals = toTotal.Select(r => r.Sum()).ToArray();