单个LINQ表达式可以计算DataSet中的多个列

时间:2012-07-07 00:42:21

标签: c# .net linq

我有一个DataSet,其中包含多行和多列(如DataSet所示)。我需要在底部创建一个计数行,每列的总和。我想用一个LINQ表达式来做这个,因为它将简化我的一堆代码。我可以像这样得到一个列的总数:

var a = (from m in month
         where <some long expression>
         select m["BGCO_MINUTES"] as Decimal?).Sum();

但是,我也想要其他列的总计。我不想使用多个LINQ表达式,因为那里还有一个复杂的 where 子句,我正在做几个带有各种表达式的计数行,只想循环遍历这个集合一次。我也不想自己手动循环遍历数据集并将总计加起来,因为我创建了许多这些计数行并认为它会更加混乱。

我想要的是一个包含BGCO_MINUTES800IB_MINUTESTSDATA_MINUTES的匿名类型。

有没有办法做到这一点?

2 个答案:

答案 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成本),我认为它比后一个版本更可读 - 确保在使用不易理解的版本之前,性能差异是值得的。