1

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

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

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

我想要的是一个匿名类型,它总共包含BGCO_MINUTES,800IB_MINUTESTSDATA_MINUTES.

有没有办法做到这一点?

4

2 回答 2

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;
});
于 2012-07-07T00:49:37.880 回答
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 成本),我认为它比后一个版本更具可读性 - 确保在使用不太容易理解的版本之前,性能差异是值得的。

于 2012-07-07T01:02:48.253 回答