Search code examples
c#linqdatatabledatasetlinq-to-dataset

Remove rows with same column value from DataTable and add corresponding values


I have a DataTable with multiple columns. If the value of certain column repeats, I need to remove that row and add the quantities against it. For example, following datatable

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

would become:

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

This is what I did

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

It removes the extra row but doesn't add up the quantities. So please help me in this regard.


Solution

  • You can use Sum. You just have to find the duplicate-rows first:

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

    Now you can use them to get the sum and to remove the redundant rows from the table.

    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);
    }
    

    Or in one query which creates a new 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();
    

    However, even the second approach modifies the original table which might be undesired since you use CopyToDatatable to create a new DataTable. You need to clone the original table(DataTable newTable = dt.Clone();) to get an empty table with the same schema. Then use NewRow + ItemArray.Clone() or table.ImportRow to create a real clone without modifying the original data.

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

    Edit: Here is an example how you can create a clone without touching the original table:

    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);
        }
    }