【问题标题】:Remove rows with same column value from DataTable and add corresponding values从 DataTable 中删除具有相同列值的行并添加相应的值
【发布时间】:2013-08-30 01:29:17
【问题描述】:

我有一个包含多列的 DataTable。如果某列的值重复,我需要删除该行并添加数量。比如下面的数据表

ITEM    QTY
------------
1       20
2       10
2       10
3       20

会变成:

ITEM    QTY
-----------
1       20
2       20
3       20

这就是我所做的

var table = dt.AsEnumerable() 
.GroupBy(row => row.Field("ITEM")) 
.Select(group => group.First()) 
.CopyToDataTable();

它会删除多余的行,但不会累加数量。所以请在这方面帮助我。

【问题讨论】:

标签: c# linq datatable dataset linq-to-dataset


【解决方案1】:

您可以使用Sum。你只需要先找到重复的行:

var dupGroups = dt.AsEnumerable()
    .GroupBy(row => row.Field<int>("ITEM"))
    .Where(g => g.Count() > 1);

现在您可以使用它们来获取总和并从表中删除多余的行。

foreach (var group in dupGroups)
{
    DataRow first = group.First();
    int sum = group.Sum(r => r.Field<int>("QTY"));
    first.SetField("QTY", sum);
    foreach (DataRow row in group.Skip(1))
        dt.Rows.Remove(row);
}

或者在一个查询中创建一个新的DataTable

DataTable newTable = dt.AsEnumerable()
    .GroupBy(row => row.Field<int>("ITEM"))
    .Select(g => 
    {
        DataRow first = g.First();
        if (g.Count() > 1)
        {
            int sum = g.Sum(r => r.Field<int>("QTY"));
            first.SetField("QTY", sum);
        }
        return first;
    })
    .CopyToDataTable();

但是,即使是第二种方法也会修改原始表,因为您使用CopyToDatatable 创建新的DataTable,所以这可能是不受欢迎的。您需要克隆原始表(DataTable newTable = dt.Clone();)以获取具有相同架构的空表。然后使用NewRow + ItemArray.Clone()table.ImportRow 在不修改原始数据的情况下创建一个真正的克隆。

见:C# simple way to copy or clone a DataRow?

编辑:这是一个示例,您可以在不触及原始表格的情况下创建克隆:

DataTable newTable = dt.Clone();
var itemGroups = dt.AsEnumerable()
    .GroupBy(row => row.Field<int>("ITEM"));
foreach (var group in itemGroups)
{
    DataRow first = group.First();
    if (group.Count() == 1)
        newTable.ImportRow(first);
    else
    {
        DataRow clone = newTable.Rows.Add((object[])first.ItemArray.Clone());
        int qtySum = group.Sum(r => r.Field<int>("QTY"));
        clone.SetField("QTY", qtySum);
    }
}

【讨论】:

  • 感谢您的回答和 cmets。第二种方法很有帮助。
  • @Sara:但第二种方法是最“危险”的,因为它以一种微妙的方式修改了两个表。如果我不想创建一个新表,我会使用第一个,如果我想创建一个带有求和值的副本表,我会使用table.Clone() + ImportRow
  • @Sara:添加了一个示例(未经测试)来展示如何在不修改原始表的情况下创建包含汇总数据的克隆。
  • 感谢您的努力。我使用了您的第二种方法并对其进行了测试。在我看来,原始表保持不变。至少行数保持不变。我不明白修改原始表格的微妙方式。
  • @Sara:在我的第二种方法(或 Cuong Le 的方法)中,“修改原始表的微妙方式”位于 first.SetField("QTY", sum);。这会更新原始表的现有 DataRow 实例,因此数据会发生更改。因此,您将以相同数量的行结束,但在一个 DataRow 上具有总计数据。最后的CopyToDataTable 创建一个新的DataTable 并将所有行复制到其中。但是,旧表现在已“损坏”。我的第一种方法更清楚,因为它只修改原始表而不创建新表。顺便说一句,考虑接受一个答案:)
【解决方案2】:

这不会改变你原来的DataTable

var table = dt.Copy().AsEnumerable()
                      .GroupBy(row=>row["ITEM"])
                      .Select(g=> {
                                DataRow dr = g.First();
                                dr.SetField("QTY", g.Sum(x=>x.Field<int>("QTY")));
                                return dr;
                             })
                      .CopyToDataTable();

【讨论】:

  • 你也不要在任何地方使用dr
  • @musefan 谢谢,我不知道为什么我打错了。那将是dr
【解决方案3】:
var table = dt.AsEnumerable() 
    .GroupBy(row => row.Field<int>("ITEM")) 
    .Select(group => {
        var row = group.First();
        row['QTY'] = group.Sum(x => x.Field<int>('QTY'));
        return row;
    }).CopyToDataTable();

【讨论】:

  • 但是,这会修改原始表,这可能是不受欢迎的,因为 OP 使用 CopyToDatatable 创建新的 DataTable。顺便说一句,同样的问题有my second approach。需要克隆原表,使用NewRow+ItemArray.Clone()table.ImportRow创建真正的克隆,不修改原数据。
  • @Cuong Le 谢谢。有用。它修改了原始版本,但这是次要问题。
猜你喜欢
  • 2013-03-17
  • 1970-01-01
  • 1970-01-01
  • 2022-12-16
  • 2017-11-07
  • 2014-12-15
  • 2021-11-02
  • 2022-12-17
  • 2021-09-12
相关资源
最近更新 更多