简体   繁体   中英

c# DataTable: More efficient Group By and Sum?

I merge two similar tables, where I have 2 fields (ID and Quantity) and end up with a table where I can have multiple records for the same ID. I want the resulting table to have only 1 record for each ID, while SUMMING the respective Quantities for each ID. After long Google search I came up with this code:

    DataTable dt1 = new DataTable("Table1");
    DataTable dt2 = new DataTable("Table2");

    dt1.Columns.Add("ID", typeof(Int32));
    dt1.Columns.Add("Quantity", typeof(Int32));
    dt1.Rows.Add(new object[] { 1, 1 });
    dt1.Rows.Add(new object[] { 2, 2 });
    dt1.Rows.Add(new object[] { 3, 3 });
    dt1.Rows.Add(new object[] { 4, 4 });

    dt2.Columns.Add("ID", typeof(Int32));
    dt2.Columns.Add("Quantity", typeof(Int32));
    dt2.Rows.Add(new object[] { 1, 100 });
    dt2.Rows.Add(new object[] { 3, 100 });
    dt2.Rows.Add(new object[] { 4, 100 });

    dt1.Merge(dt2);

    var datas = dt1.AsEnumerable()
       .GroupBy(r => new { Col1 = r["ID"] })
       .Select(g => g.First()["Quantity"] = g.Sum(x => int.Parse(x["Quantity"].ToString())))
       .ToList();

    dt1 = dt1.AsEnumerable().GroupBy(r => new { Col1 = r["ID"] })
        .Select(x => x.First()).CopyToDataTable();

However, I feel that there is a way to do this more efficiently as the table gets scanned twice in this case. Does anyone have any suggestions?

One more thing, as a bonus question I would like to find a total Quantity across the entire resulting table, idealy in an efficient way (that is WHILE grouping it).

UPDATE: yes I know, DataTable is not a wise data structure, but due to the nature of our project I am forced to work with them. I would much appreciate a suggestion on how to use an intermediary data structure here but in the end I need a DataTable.

//your method
public void YourMethod()
{
     Dictionary<int, int> result = new Dictionary<int, int>();

     int length = 0;

     if(dt1.Rows.Count > dt2.Rows.Count)
        length = dt1.Rows.Count
     else
         length = dt2.Rows.Count

     for(int i=0; i < length - 1; i++)
     {
         AddRowValue(dt1, result, i);
         AddRowValue(dt2, result, i);
     }  

}


public AddRowValue(DataTable tbl, Dictionary<int, int> dic, int index)
{
    if( index > tbl.Rows.Count)
       return;

    DataRow row = tbl.Rows[index];

    int idValue = Convert.ToInt32(row["ID"]);
    int quantityValue = Convert.ToInt32(row["Quantity"]);

    if(dic.Keys.Contains(idValue)
         dic[idValue] = dic[idValue] + quantityValue;
    else
         dic.Add(idValue, quantityValue);
}

You need something like this, you can use dictionary at the end the result will be stored in the dictionary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM