You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET/C# WinForms中用LINQ优化DataTable发票汇总性能

高效汇总DataTable发票组数据并更新原表

需求背景

现有包含商品成本、税费等字段的DataTable,其中supplier_id_invoice_number_combo列值相同的行属于同一发票组,需按该列:

  1. 汇总total_cost_price_of_item列得到商品总成本
  2. 计算每组的总税费(CGST金额+SGST金额,按行内税率和成本计算后求和)
  3. 将上述两个汇总值更新到原表对应发票组的所有行的invoice_item_amount和invoice_tax_amount字段

当前嵌套循环遍历的方式性能低下(130+行时已明显卡顿),需优化实现方式。

高效实现方案

方案1:使用LINQ分组计算(VB.NET)

通过LINQ一次性完成分组与汇总计算,再遍历原表更新,仅需两次遍历(分组一次,更新一次):

' 首先通过LINQ分组计算每个发票组的汇总值
Dim invoiceSummaries = From row In my_format_dt.AsEnumerable()
                       Group row By combo = row.Field(Of String)("supplier_id_invoice_number_combo") Into Group
                       Select New With {
                           .Combo = combo,
                           .TotalItemAmount = Math.Round(Group.Sum(Function(r) r.Field(Of Double)("total_cost_price_of_item")), 2),
                           .TotalTaxAmount = Math.Round(Group.Sum(Function(r) 
                               (r.Field(Of Double)("cgst_percentage") / 100 * r.Field(Of Double)("total_cost_price_of_item")) + 
                               (r.Field(Of Double)("sgst_percentage") / 100 * r.Field(Of Double)("total_cost_price_of_item"))
                           ), 2)
                       }

' 将汇总结果转成字典,方便快速查找(可选,进一步提升更新效率)
Dim summaryDict = invoiceSummaries.ToDictionary(Function(s) s.Combo)

' 遍历原表更新对应字段
For Each row In my_format_dt.AsEnumerable()
    Dim combo = row.Field(Of String)("supplier_id_invoice_number_combo")
    If summaryDict.ContainsKey(combo) Then
        row.SetField("invoice_item_amount", summaryDict(combo).TotalItemAmount)
        row.SetField("invoice_tax_amount", summaryDict(combo).TotalTaxAmount)
    End If
Next

方案2:使用字典缓存汇总结果(更直观的O(N)复杂度)

先遍历一次原表计算所有发票组的汇总值并存入字典,再遍历一次原表完成更新,全程仅两次遍历:

Dim summaryDict As New Dictionary(Of String, (TotalItem As Double, TotalTax As Double))

' 第一次遍历:计算每个发票组的汇总值
For Each row In my_format_dt.AsEnumerable()
    Dim combo = row.Field(Of String)("supplier_id_invoice_number_combo")
    Dim itemCost = row.Field(Of Double)("total_cost_price_of_item")
    Dim cgstAmt = (row.Field(Of Double)("cgst_percentage") / 100) * itemCost
    Dim sgstAmt = (row.Field(Of Double)("sgst_percentage") / 100) * itemCost

    If summaryDict.ContainsKey(combo) Then
        summaryDict(combo) = (
            summaryDict(combo).TotalItem + itemCost,
            summaryDict(combo).TotalTax + cgstAmt + sgstAmt
        )
    Else
        summaryDict.Add(combo, (itemCost, cgstAmt + sgstAmt))
    End If
Next

' 对字典中的汇总值做四舍五入
For Each key In summaryDict.Keys.ToList()
    summaryDict(key) = (
        Math.Round(summaryDict(key).TotalItem, 2),
        Math.Round(summaryDict(key).TotalTax, 2)
    )
Next

' 第二次遍历:更新原表字段
For Each row In my_format_dt.AsEnumerable()
    Dim combo = row.Field(Of String)("supplier_id_invoice_number_combo")
    If summaryDict.ContainsKey(combo) Then
        row.SetField("invoice_item_amount", summaryDict(combo).TotalItem)
        row.SetField("invoice_tax_amount", summaryDict(combo).TotalTax)
    End If
Next

性能优化说明

  • 原实现的时间复杂度为O(M*N)(M为唯一发票组数量,N为总行数),当数据量增大时性能急剧下降
  • 两种新方案的时间复杂度均为O(N)(字典查找为O(1)),仅需2次遍历原表,性能提升显著
  • 推荐使用方案2,逻辑更直观,避免LINQ分组可能带来的微小性能开销

内容的提问来源于stack exchange,提问作者Ankit Srivastava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:27:04