【问题标题】:c# DataTable: More efficient Group By and Sum?c# DataTable:更高效的 Group By 和 Sum?
【发布时间】:2016-02-12 09:44:35
【问题描述】:

我合并了两个相似的表,其中有 2 个字段(ID 和 Quantity),最后得到一个表,其中我可以为同一个 ID 包含多个记录。我希望结果表对于每个 ID 只有 1 条记录,同时对每个 ID 的相应数量求和。经过长时间的谷歌搜索,我想出了这个代码:

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

但是,我觉得有一种方法可以更有效地执行此操作,因为在这种情况下,表格会被扫描两次。有人有什么建议吗?

还有一件事,作为一个额外的问题,我想在整个结果表中找到一个总数量,理想情况下是以一种有效的方式(即同时对其进行分组)。

更新: 是的,我知道,DataTable 不是一个明智的数据结构,但由于我们项目的性质,我不得不使用它们。我非常感谢关于如何在这里使用中间数据结构的建议,但最后我需要一个 DataTable。

【问题讨论】:

  • 嗯,可以通过多种方式完成。例如,您可以摆脱 linq 方法并在单个循环中扫描您的表,同时在单独的 Dictionary<int, int> 中对数量求和,其中 ID 作为键,数量作为值。
  • 我只会对数据进行排序,然后进行一个简单的循环,同时通过这两个循环并在需要时求和。或者如果有很多数据并且排序需要时间,那么安迪的评论很好。也将允许轻松获得总数。这是一个例子,其中几行代码比 LINQ 工作得更好(尽管有人可能也想出了一个 LINQ 版本)。另一方面,DataTables 的性能很差,所以如果你有一个庞大的数据集,它们并不是最好的。
  • 你为什么要使用数据表,它们很烂
  • @SamiKuhmonen 那么你会建议什么数据结构呢?我收到我的 DataTable-s 作为 SQL 请求的结果(这是我们项目的性质),但在最后一步我需要合并它们。我们认为增大原始 SQL 请求是不明智的,因此我需要先将 DataTable 转换为其他结构。那么你有什么建议呢?另外,我希望有一个指向字典方法的代码示例的链接。
  • 数据表在内存中。与磁盘 IO 和网络 IO 相比,它们应该快得令人眼花缭乱。你真的在这里得到任何好处吗?

标签: c# datatable group-by sum


【解决方案1】:
//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);
}

你需要这样的东西,你可以在最后使用字典,结果将存储在字典中。

【讨论】:

  • 加载字典会扼杀任何性能优势。毕竟,分组的作用是相同的
  • @PanagiotisKanavos 我不确定 group by 在 linq 下是如何工作的,但至少在这里你使用过一次。在他的代码中,他将 2 分组。他可以通过秒表轻松检查哪种方法更好。
  • @mybirthname 使答案完整,您需要添加代码,更新初始表以包含所有唯一 ID ONCE 和正确的数量总和。
  • 不用再用datatable了,可以用字典了。
  • 我没有看到任何遗漏,请不要想,尝试一下,如果您不想忽略答案。我们用一个循环扫描两个表。
猜你喜欢
  • 2012-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-30
相关资源
最近更新 更多