【问题标题】:Linq syntax to find subtotal of grouped rows in a DataTable and update the DataTable用于查找 DataTable 中分组行的小计并更新 DataTable 的 Linq 语法
【发布时间】:2016-03-30 18:38:39
【问题描述】:

我一直在为这个问题摸不着头脑......我在内存中有一个表,一个结构如下的 DataTable:

Input:
   ID   |   Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
    0    |   09310   |    123    |    6.0    |    ?
-----------------------------------------------------------------

我希望使用 Linq 执行以下操作(我对 Linq 很陌生!)

对于同一帐户的每一行,将所有付款加在一起并写入或更新小计字段 我不想折叠表格,发票号码会有所不同。我的想法是有两种方法可以做到这一点

(A)从所有记录的空白小计列开始...来自付款的值将加在一起,然后写入小计列

(B) 创建表时,我将付款值复制到小计字段中。稍后,linq 只需添加/替换同一列中的值

所以我们会忽略 ID 和 Invoice 字段;它的 ACCOUNT 和 SUBTOTAL(如果使用样式 (A),还有 PAYMENT)

(A) Input: *(note that there are two records for 123)*
   ID   |   Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
    0    |   03310   |    123    |    6.0    |    
-----------------------------------------------------------------
    1    |   09728   |    123    |    4.0    |    
-----------------------------------------------------------------
    2    |   07731   |    559    |    18.0   |    
-----------------------------------------------------------------

 

(B) Input:
   ID   |   Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
    0    |   03310   |    123    |    6.0    |    6.0
-----------------------------------------------------------------
    1    |   09728   |    123    |    4.0    |    4.0
-----------------------------------------------------------------
    2    |   07731   |    559    |    18.0   |    18.0
-----------------------------------------------------------------

 

Result:
   ID   |   Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
    0    |   03310   |    123    |    6.0    |    10.0
-----------------------------------------------------------------
    1    |   09728   |    123    |    4.0    |    10.0
-----------------------------------------------------------------
    2    |   07731   |    559    |    18.0   |    18.0
-----------------------------------------------------------------

因此,每个小计单元格将包含每个唯一帐户的所有付款总额

我认为样式 (B) 会更简单,因为我们只需要处理这两列

对于样式(B),我尝试过类似

rpTable.AsEnumerable().GroupBy(g => int.Parse(g.Field<string>("Account"))).Select(g => g.Sum(p => p.Field<decimal>("SubTotal")));

但我可以说它缺少一些东西.....hmmmm

【问题讨论】:

    标签: c# linq datatable subtotal linq-group


    【解决方案1】:

    通过使用 Select,您不会更新表格。这只是返回所选值的 IEnumerable。

    您要做的是将列添加到表中,然后填充它:

    var subTotalByAccount = table.AsEnumerable()
                .GroupBy(g => g.Field<string>("Account"))
                .Select(g => new { Account = g.Key, SubTotal = g.Sum(p => p.Field<decimal>("Payment")) })
                .ToDictionary(t => t.Account, t => t.SubTotal);
    
    table.Columns.Add("SubTotal", typeof(decimal));
    foreach (var row in table.AsEnumerable())
    {
                row.SetField(columnName: "SubTotal", value: subTotalByAccount[row.Field<string>("Account")]);
    }
    

    【讨论】:

      【解决方案2】:

      非常感谢 timcbaoth,是的,我同意你所说的。我试图支持你的帖子,但系统说我可能不会:-(
      我已经使用蛮力解决了(如下),但我也会评估您的解决方案!再次感谢!!

              var query = from row in rpTable.AsEnumerable()
                          group row by int.Parse(row.Field<string>("Account")) into grp
                          orderby grp.Key
                          select new
                          {
                              Id = grp.Key,
                              Sum = grp.Sum(r => r.Field<decimal>("Payment"))
                          };
              foreach (var grp in query)
              {
                  rpTable.Select("Account ="+grp.Id).ToList<DataRow>().ForEach(r=>r["Payment"] = grp.Sum);
              }
      

      【讨论】:

      • 太好了,你想通了!你的方法似乎(几乎)和我的一样。我在 msdn 上找不到有关它的详细信息,但我相信 rpTable.Select 具有线性运行时,这意味着在我的方法中使用字典可能会获得一些常数因子加速。但正如我所说,情况可能并非如此。
      • 顺便说一句。只是一个小评论:您也可以使用插值字符串: $"Account = {grp.Id}" 这可以使语句更具可读性。 msdn.microsoft.com/en-us/library/dn961160.aspx
      • 感谢您的评论。非常感谢您的帮助!
      【解决方案3】:

      我发现了一个阴险的小错误,仅供参考:

      OLD: rpTable.Select("Account ="+grp.Id).ToList<DataRow>().ForEach(r=>r["Payment"] = grp.Sum);   
      NEW: rpTable.Select("Account ='"+ grp.Id +"'").ToList<DataRow>().ForEach(r => r["Payment"] = grp.Sum);
      

      【讨论】:

      • 我不是反对者,只是为了记录,但我认为您可以编辑自己的答案。然后清除这个并恢复一点。
      猜你喜欢
      • 2015-10-22
      • 1970-01-01
      • 1970-01-01
      • 2011-09-28
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      相关资源
      最近更新 更多