Linq 语法查找 DataTable 中分组行的小计并更新 DataTable
Linq syntax to find subtotal of grouped rows in a DataTable and update the DataTable
我一直在为这个问题挠头...我在内存中有一个table,一个结构如下的DataTable:
Input:
ID | Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
0 | 09310 | 123 | 6.0 | ?
-----------------------------------------------------------------
并且我希望使用 Linq 执行以下操作(我对 Linq 还很陌生!)
对于同一账户的每一行,将所有付款加在一起并写入或更新小计字段
我不想折叠 table,发票编号会有所不同。我的想法是有两种方法可以做到这一点
(A) 从所有记录的空白小计列开始...来自付款的值将被加在一起,然后写入小计列
(B) 当 table 创建时,我将付款值复制到小计字段中。稍后,linq 只需 add/replace 同一列中的值
因此我们将忽略 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")));
但我可以看出它缺少了一些东西.....嗯嗯
通过使用 Select,您将不会更新 table。这只是 returns 所选值的 IEnumerable。
您要做的是将列添加到 table,然后填写它:
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")]);
}
非常感谢timcbaoth,是的,我同意你说的。我试图给你的 post 投票,但系统说我可能不会:-(
我已经使用蛮力解决了(下面),但我也会评估您的解决方案!再次感谢!!
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);
}
我发现了一个隐藏的小错误,所以仅供参考:
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);
我一直在为这个问题挠头...我在内存中有一个table,一个结构如下的DataTable:
Input:
ID | Invoice | Account | Payment | Subtotal
-----------------------------------------------------------------
0 | 09310 | 123 | 6.0 | ?
-----------------------------------------------------------------
并且我希望使用 Linq 执行以下操作(我对 Linq 还很陌生!)
对于同一账户的每一行,将所有付款加在一起并写入或更新小计字段 我不想折叠 table,发票编号会有所不同。我的想法是有两种方法可以做到这一点
(A) 从所有记录的空白小计列开始...来自付款的值将被加在一起,然后写入小计列
(B) 当 table 创建时,我将付款值复制到小计字段中。稍后,linq 只需 add/replace 同一列中的值
因此我们将忽略 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")));
但我可以看出它缺少了一些东西.....嗯嗯
通过使用 Select,您将不会更新 table。这只是 returns 所选值的 IEnumerable。
您要做的是将列添加到 table,然后填写它:
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")]);
}
非常感谢timcbaoth,是的,我同意你说的。我试图给你的 post 投票,但系统说我可能不会:-(
我已经使用蛮力解决了(下面),但我也会评估您的解决方案!再次感谢!!
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);
}
我发现了一个隐藏的小错误,所以仅供参考:
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);