【问题标题】:Comparing Two Datasets - Slow比较两个数据集 - 慢
【发布时间】:2014-08-30 10:55:10
【问题描述】:

我有一组数据,格式如下,虽然非常简化:

  • 经销商名称、帐户代码、价值
  • 经销商1, A-1, 5
  • Dealer2, A-1, 10
  • 经销商1、A-2、20
  • Dealer2, A-2, 15
  • 经销商3、A-3、5

我正在努力实现最终结果,该结果为我提供由 AccountCode 汇总的数据,因此在上述数据的情况下如下:

  • 账户代码,价值
  • A-1, 15
  • A-2, 35
  • A-3, 5

我通过创建一个名为 OutputData 的不同帐户代码数组来完成此操作,然后通过数据将帐户代码与 SelectedDealerData 中的同一字段进行比较并将其添加到现有值中:

For i = 0 To UBound(SelectedDealerData)
    For j = 0 To UBound(OutputData)
        If SelectedDealerData(i).AccountNumber = OutputData(j).AccountNumber And SelectedDealerData(i).Year = OutputData(j).Year Then
            OutputData(j).Units = OutputData(j).Units + SelectedDealerData(i).Units
            Exit For
        End If
    Next j
Next i

大约有 10,00 个经销商和 600-1000 个帐户代码,因此这意味着很多不必要的循环。

有人可以为我指出更有效的解决方案吗?我在想某种字典比较,但我不确定如何实现它。

【问题讨论】:

  • 这是在 Excel / Access 中吗?如果是在 Excel 中,为什么不直接使用 =SUMIFS 之类的工作表函数

标签: arrays vba dictionary collections


【解决方案1】:

为字典添加对 Microsoft Scripting Runtime 的引用:

    Dim aggregated As Dictionary
    Set aggregated = New Dictionary

    For i = 0 To UBound(SelectedDealerData)
        With SelectedDealerData(i)
            If aggregated.Exists(.AccountCode) Then
                aggregated(.AccountCode) = aggregated(.AccountCode) + .Value
            Else
                aggregated(.AccountCode) = .Value
            End If
        End With
    Next

    For Each Key In aggregated.Keys
        Debug.? Key, aggregated(Key)
    Next

【讨论】:

    【解决方案2】:

    代码很慢,因为这里有 1000 万次比较和赋值操作 (10,000 x 1000)。

    此外,通过集合循环不是很有效,但对此无能为力,因为设计已经设置并保持原样。

    您可以通过两种方法来提高效率(您可以立即对代码进行计时,并在这些步骤之后查看节省的百分比)。

    1. And 正在进行两个条件检查。即使第一个为假(无短路),VBA 也会评估两者。所以放置嵌套的if then 条件,这样如果第一个条件失败,您就不会继续检查第二个条件。此外,在外部 if 语句中保持条件更有可能失败(因此它会快速失败并移动到下一个元素)。在最好的情况下,你会遇到一个小减速,在最坏的情况下,你不会更糟。

    2. 这里发生了太多的比较。更改它为时已晚,但是如果您可以对集合进行排序或构建一个保持其排序顺序的索引(如果您愿意,可以将该索引数组保存在电子表格中),您可以根据以下伪代码遍历循环。排序应基于名为 Account_Number_Year 的复合字段(只需将它们连接起来)

    3. 您可以在 Alex K 建议的字典结构中使用此连接字段。因此您可以在第二个字典中查找此联合字段,然后根据需要进行操作。

    尝试在 VBA 中完全实现它的代码:

    'Assuming both arrays are sorted
    For i = 0 to Ni
        MatchingIndex = _
            BinarySearchForAccNumberYear(SelectedUserData(i).AccountNumberYear)
    Next i
    

    您可以查找 Binary Search here

    这会将您的时间复杂度从 O(n^2) 降低到 O(n log n),并且您的代码运行速度将提高一个数量级。

    【讨论】:

      猜你喜欢
      • 2011-07-30
      • 2015-07-10
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 2011-09-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多