我有一个DataSet
,其中包含多行和多列(如DataSet所示)。我需要在底部创建一个计数行,每列的总和。我想用一个LINQ表达式来做这个,因为它将简化我的一堆代码。我可以像这样得到一个列的总数:
var a = (from m in month
where <some long expression>
select m["BGCO_MINUTES"] as Decimal?).Sum();
但是,我也想要其他列的总计。我不想使用多个LINQ表达式,因为那里还有一个复杂的 where 子句,我正在做几个带有各种表达式的计数行,只想循环遍历这个集合一次。我也不想自己手动循环遍历数据集并将总计加起来,因为我创建了许多这些计数行并认为它会更加混乱。
我想要的是一个包含BGCO_MINUTES
,800IB_MINUTES
和TSDATA_MINUTES
的匿名类型。
有没有办法做到这一点?
答案 0 :(得分:2)
使用Aggregate代替Sum,因为它更灵活 - 您可以使用对象(或简单字典)在迭代每行时保存各列的总和。
(未编译的代码)
class SumObject {
public float First;
public float Second;
}
var filtered = (from m in month
where <some long expression>
select m;
filtered.Aggregate(new SumObject(), (currentSum, item)=> {
currentSum.First += item.First;
currentSum.Second += item.Second;
return currentSum;
});
答案 1 :(得分:2)
你可以这样做:
// run the filters once and get List<DataRow> with the matching rows
var list = (from m in month
where <some long expression>
select m).ToList();
// build the summary object
var result = new {
BGCO_MINUTES = list.Sum(m => m["BGCO_MINUTES"] as Decimal?),
_800IB_MINUTES= list.Sum(m => m["800IB_MINUTES"] as Decimal?),
}
这就是假设你的where子句不仅要输入很长时间,而且计算成本也很高。 将每列迭代一次列表。
如果你真的想只迭代列表一次,你可以用Enumerable.Aggregate来做,但代码不那么优雅(在我看来):
// run the filters once and get List<DataRow> with the matching rows
var a = (from m in month
where <some long expression>
select m)
.Aggregate( new { BGCO_MINUTES = (decimal?)0m,
_800IB_MINUTES = (decimal?)0m },
(ac,v) => new { BGCO_MINUTES = ac.BGCO_MINUTES + (decimal?)v["BGCO_MINUTES"],
_800IB_MINUTES = ac._800IB_MINUTES + (decimal?)v["800IB_MINUTES"] });
就像我说的,我认为它不如第一个版本优雅,但它应该有效。即使第一个需要临时副本的值匹配where子句(内存成本)和1通过列表的每个字段(CPU成本),我认为它比后一个版本更可读 - 确保在使用不易理解的版本之前,性能差异是值得的。