使用多个“For”和“if”语句加速 VBA 宏

Posted

技术标签:

【中文标题】使用多个“For”和“if”语句加速 VBA 宏【英文标题】:Speeding up VBA Macro with multiple 'For' and 'if' statements 【发布时间】:2015-12-21 21:39:14 【问题描述】:

此宏需要 2 分钟以上才能运行。优化宏的最佳方法是什么?

Sub Time_Color(z, k)

Application.DisplayAlerts = False

For Each cell In Sheet1.Range("C" & z & ":" & "LZ" & z)
    If cell.Value <> "x" Then
           If cell.Value < Sheet3.Range("D" & k) Then
              cell.Interior.ColorIndex = 37
              cell.Offset(1, 0).Value = Sheet4.Range("D" & k).Value & "_" & Sheet4.Cells(k, 5).Value
           End If

        For j = 5 To 1000 Step 2
         If cell.Value > Sheet3.Cells(k, j).Value And cell.Value < Sheet3.Cells(k, j + 1).Value Then
         cell.Interior.ColorIndex = 37
         cell.Offset(1, 0).Value = Sheet4.Cells(k, j + 1).Value & "_" & Sheet4.Cells(k, j + 2).Value
        End If
       Next j

       For j = 4 To 1000 Step 2
       If cell.Value >= Sheet3.Cells(k, j).Value And cell.Value <= Sheet3.Cells(k, j + 1).Value Then
       cell.Interior.ColorIndex = 43
       cell.Offset(1, 0).Value = Sheet4.Cells(k, j).Value & "_" & Sheet4.Cells(k, j + 1).Value
       End If
       Next j
End If
Next cell
Application.DisplayAlerts = True

End Sub

我正在为 24 种不同的 z,k 组合运行此宏。

【问题讨论】:

由于您在两个循环中比较完全相同的值,因此您只需要其中一个。 运行时关闭屏幕更新和计算。计算应在您的 Sub 结束之前重置(ScreenUpdating 将自行重置) 在循环中尽可能少地进行单元格操作,但尝试在一个范围内收集需要更改的单元格并在循环外一次性操作它们。 Sheet3 行中的值是否总是升序?如果是这样,您不必循环,可以使用WorksheetFunction.Match 来查找位置,而不是将 j 步进到 1000。 @TimWilliams 您应该将您的评论变成答案,以便 G.Fox 将其标记为正确。 【参考方案1】:

尝试缓存尽可能多的数据,例如 Sheet3.Range("D" &amp; k) 在整个函数中都是常量。

最内层循环的每个实例都会查询该单元格。如果你把它放在这个函数的开头,它将被查找一次,然后用于函数的其余部分。

编辑: 在这个问题的 cmets 中 - 我认为 - Tim Williams 提供了一个更好的答案,这是 VBA 特有的:

在运行时关闭屏幕更新和计算。计算 应在您的 Sub 结束之前重置(ScreenUpdating 将重置 本身)

【讨论】:

我尝试通过 'Dim r as Range' 然后 'r= Range("D" & k)' 执行此操作,但我得到运行时错误 - 91: Object variable or With block variable没有设置。抱歉,如果这是一个愚蠢的问题,我对这一切都是新手。 设置对象变量时使用Set,所以Set r = Range("D" &amp; k)【参考方案2】:

我不完全确定您要完成什么,但您的循环似乎在大范围内迭代以找到满足两个给定条件之一的单元格的最后一个实例(您的两个循环) .

如果这是目标,为什么不从后面开始呢?根据您的工作表的外观,这可能会快得多!

我还做了一些其他的改变。让我知道它是如何工作的。

注意还要在底部包含函数(从this answer 窃取),或将其替换为您选择的函数。

Sub Time_Color(z, k)
    Application.DisplayAlerts = False
    Application.ScreenUpdating = False

    Dim loopVal, loopVal2, loopVal3 As Variant
    Dim setOdd, setEven, OddEven As Boolean

    Dim compVal, compVal2, compVal3 As Variant
    compVal = Sheet3.Range("D" & k).Value
    compVal2 = Sheet4.Range("D" & k).Value
    compVal3 = Sheet4.Cells(k, 5).Value


    For Each cell In Sheet1.Range("C" & z & ":" & "LZ" & z)
        If cell.Value <> "x" Then
            If cell.Value < compVal Then
                cell.Interior.ColorIndex = 37
                cell.Offset(1, 0).Value = compVal2 & "_" & compVal3
            End If

            For j = 1000 To 4 Step -1
                loopVal = Sheet3.Cells(k, j).Value
                loopVal2 = Sheet3.Cells(k, j + 1).Value
                loopVal3 = Sheet4.Cells(k, j + 1).Value
                OddEven = OddOrEven(j)

                If OddEven = True Then
                    If cell.Value > loopVal And cell.Value < loopVal2 Then
                        cell.Interior.ColorIndex = 37
                        cell.Offset(1, 0).Value = loopVal3 & "_" & Sheet4.Cells(k, j + 2).Value
                        setOdd = True
                    End If
                Else
                    If cell.Value >= loopVal And cell.Value <= loopVal2 Then
                        cell.Interior.ColorIndex = 43
                        cell.Offset(1, 0).Value = Sheet4.Cells(k, j).Value & "_" & loopVal3
                        setEven = True
                    End If
                End If

                If setEven = True And setOdd = True Then Exit For
            Next j
        End If
    Next cell
    Application.DisplayAlerts = True
End Sub


Function OddOrEven(a As Integer) As Boolean ' Returns TRUE if a is an odd number
    If a - (2 * (Fix(a / 2))) <> 0 Then OddOrEven = True
End Function

【讨论】:

我正在尝试制定一个可以更新的时间表,以反映本周每个工作站的当前作业顺序。我设置了一个“更新时间”宏,以便它首先通过并在单元格中用“x”标记任何过去的日子/时间,以及用户标记为非计划时间的任何单元格,即取力器/假期。从这里开始,“更新时间”在空单元格中分配值,增量为 0.5,这是一周中剩余的可用“工作时间”。然后,我将表 3 按每个工作中心的设置和运行时间(以小时为单位)进行细分。 Time_Color 与每个颜色相匹配。

以上是关于使用多个“For”和“if”语句加速 VBA 宏的主要内容,如果未能解决你的问题,请参考以下文章

数组中多个 if 语句的 VBA 代码

excel VBA用户定义函数中是不是可以有多个if语句

VBA if语句

VBA if...else语句

VBA if...elseif...else语句

vue中v-for 和v-if嵌套使用