【问题标题】:Condense largely(Unpractical) loop based VBA code; nested For...Next loops压缩大量(不实用)基于循环的 VBA 代码;嵌套的 For...Next 循环
【发布时间】:2015-06-30 17:33:46
【问题描述】:

大家好,先简单介绍一下我的项目背景,然后我会跟进我的具体问题和代码。

目前我正在构建一个程序来自动化填充模板的过程。这个模板经常超过 60,000 行数据,我通过插入新的数据表并运行它来构建它的大部分以每月工作。目前所有的工作都基于我手动导入到 excel 中的一张数据表。此数据表不包含填充模板所需的所有数据,因此现在我开始引入其他数据来补充它。这里的问题在于数据关联。当我最初从一个数据表中提取数据时,我不必担心我为每一行提取的数据是否与其他行一致,因为它们都来自同一个数据表。现在我必须交叉检查两张纸上的数据,以确认它提取了正确的信息。

现在了解您需要了解的内容。我正在尝试填充将被称为理发的列,但在此之前,我需要确认我正在提取与贸易 ID 相关的正确理发编号,该贸易 ID 已填充到上一行的模板中代码。

使用我在整个项目中一直使用的类似逻辑,这是我必须执行此任务的一段代码。

    Dim anvil as Worksheet
    Dim ALLCs as worksheet
    Dim DS as worksheet
    '''''''''''''''''''''''''''''code above this line is irrelevant to answer this question
    ElseIf InStr(1, DS.Cells(x, 2), "Haircut") Then
    Anvil.Select
        For y = 1 To 80
            If Anvil.Cells(1, y) = "Haircut" Then
                For Z = 1 To 80
                    If Anvil.Cells(1, Z) = "Trade ID" Then
                        For t = 2 To 70000
                            For u = 16 To 70000
                                If Anvil.Cells(t, Z) = ALLCs.Cells(u, 34) Then
                                ALLCs.Cells(u, 27) = Anvil.Cells(t, y)
                                End If
                            Next
                        Next
                    End If
                Next
            End If
        Next

这个代码加上我的其他代码我认为理论上可以工作,但我只能想象它会花费难以置信的时间(这个程序已经需要 7 分半钟才能运行)。关于如何按照这个一般逻辑以更好的功能重写这段代码有什么建议吗?

感谢您提供任何帮助,无论您是完全修改代码,还是提供有关如何减少循环的建议。除了屏幕更新和计算建议之外,我还在寻找加快代码速度的建议。

【问题讨论】:

  • 我已经提供了关于减少代码的答案 - 但是寻求关于加速代码的一般建议有点超出 SO 的范围。如果你有一个特定的例子,那么你可以将它作为一个单独的问题发布,或者甚至将你的代码提交到 Code Review 站点——希望对你有所帮助:)
  • 哇!有 31 万亿次循环的潜力,我敢打赌,过滤器可以满足您的要求,甚至动态设置范围也有帮助,正如其他人所说,将我们链接到示例工作簿
  • 作为一名 CR 常客(也是 CR 的顶级 VBA 审阅者之一),我同意 @SOofWXLS 的观点,在 Code Review 上发布您的完整工作代码肯定会大大提高此代码的性能、可读性和可维护性。
  • 我会对此非常感兴趣。我在一家大公司工作时不确定是否合法。我想有某种知识产权的东西阻止我输入我的代码。此外,我想我必须更改一些标识符以保持某种机密性。
  • 这就是为什么您将其设为带有假数据的示例工作簿,而不是带有真实数据的实际工作簿。

标签: vba loops excel for-loop


【解决方案1】:

如果我正确理解了逻辑,那么您可以使用 .Find() 方法替换除一个循环之外的所有循环,如下所示:

'// Dimension range objects for use
Dim hdHaricut As Excel.Range
Dim hdTradeID As Excel.Range
Dim foundRng As Excel.Range

With Anvil
    With .Range("A1:A80") '// Range containing headers
        '// Find the cell within the above range that contains a certain string, if it exists set the Range variable to be that cell.
        Set hdHaircut = .Find(What:="Haircut", LookAt:=xlWhole)
        Set hdTradeID = .Find(What:="Trade ID", LookAt:=xlWhole)
    End With
    '// Only if BOTH of the above range objects were found, will the following block be executed.
    If Not hdHaricut Is Nothing And Not hdTradeID Is Nothing Then
        For t = 2 To 70000
            '// Using the .Column property of the hdTradeID range, we can see if the value of Cells(t, hdTradeColumn) exists 
            '// in the other sheet by using another .Find() method.
            Set foundRng = ALLCs.Range(ALLCs.Cells(16, 34), ALLCs.Cells(70000, 34)).Find(What:=.Cells(t, hdTradeID.Column).Value, LookAt:=xlWhole)
            '// If it exists, then pass that value to another cell on the same row
            If Not foundRng Is Nothing Then ALLCs.Cells(foundRng.Row, 27).Value = .Cells(t, hdHaircut.Column).Value
            '// Clear the foundRng variable from memory to ensure it isn't mistaken for a match in the next iteration.
            Set foundRng = Nothing
        Next
    End If
End With

【讨论】:

  • 我从不习惯 - 但是我在一个报告格式永远改变以满足用户需求的环境中工作,因此.Find() 很快成为我处理标题的最佳朋友!
  • 我不熟悉 .find 函数,因此我不确定是否会按预期工作。让我结合你的答案做一些研究,我会回复你的。在我看来,foundRng 变量看起来像是希腊语。
  • 看完之后我认为这个解决方案会很好用@SOofWXLS 你是否可以详细说明你的代码的某些部分并解释它们的功能?
  • @dom176 .Find 如果成功则返回一个Range 对象——如果它没有找到任何东西,它返回一个null 引用,在VBA 中是@987654326 @。所以If Not foobar Is Nothing Then 将在foobar 有一个实际的对象引用时执行代码。
  • 所以如果我的假设是正确的,在 .find 步骤之后 hdhaircut 将被设置为包含标题理发的列的整个范围,并且对于 hdTradeID 变量也是如此。即使在阅读了foundrng变量声明之后,我仍然不明白正在应用什么。 @Mat'sMug
猜你喜欢
  • 1970-01-01
  • 2017-03-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-01
  • 2012-11-07
  • 2018-12-03
  • 2020-12-30
  • 1970-01-01
相关资源
最近更新 更多