【问题标题】:Single LINQ expression to tally up several columns in a DataSet单个 LINQ 表达式来计算数据集中的几列
【发布时间】:2012-07-07 09:02:48
【问题描述】:

我有一个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

有什么办法吗?

【问题讨论】:

    标签: c# .net linq


    【解决方案1】:

    你可以这样做:

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

    【讨论】:

    • Hmm.. 显然,当其他人在您写作时发布回复时(或者我错过了它),SO 并没有给您一点弹出的东西。那好吧。我关于可读性的观点(除非涉及大量数据,否则性能差异可能很小)仍然成立。
    • +1。是的,简单的 Sum 更具可读性。 +您的示例没有额外的类并使用 OP 的对象。
    • 是的,我很确定这就是我将要采取的方法。我从@AlexeiLevenkov 发布的方法开始,它很快就开始变得非常混乱:) 数据不足以解决任何性能问题。
    【解决方案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;
    });
    

    【讨论】:

      猜你喜欢
      • 2011-12-05
      • 1970-01-01
      • 2017-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多