【问题标题】:Excel VBA UsedRange for multiple FOR loops, and "resetting" to make macro fasterExcel VBA UsedRange 用于多个 FOR 循环,并“重置”以使宏更快
【发布时间】:2023-03-24 05:41:01
【问题描述】:

我开发了一个宏来清理复制/粘贴的数据集,这些数据只是一系列行到具有多个列和标题的 Excel 中。为了帮助清理数据,我添加了三个 FOR LOOP 进程:

  1. 删除编号为项目符号的行
  2. 已删除无关数据(miles & minActive)
  3. 手动将其他数据集剪切/粘贴到各自的列中(steps & stepavg)

它似乎运作良好,但我想优化这个过程。在运行宏时,问题是我使用“UsedRange”来确定 FOR LOOP 1 存在多少行(大约 800 行)。在该循环期间,许多行被删除,因此它可能会从 800 过滤到 350。然后当执行 FOR LOOP 2 时,似乎 UsedRange 仍然引用 800 行,所以循环继续,从 350 过滤到 65。最后使用 FOR LOOP 3,它成功地完成了所有 65 个任务,我可以说它完成了。但是,它会继续排到第 800 行!

有什么建议可以“清除”或“重置”UsedRange 以加快此过程吗?除了这个问题,我的宏效果很好。

'Cleaning the Data
    Dim i As Long
    Dim j As Long
    Dim k As Long
    Dim maxRow As Long

    maxRow = ActiveSheet.UsedRange.Rows.Count

    'Removes all those single number rows
    For i = 2 To maxRow Step 3
        Rows(i).Select
        Selection.Delete Shift:=xlLeft
    Next i
    Range("A1").Select

    'Removes all those miles and min active data
    Dim maxRow2 As Long
    maxRow2 = ActiveSheet.UsedRange.Rows.Count
    For j = 5 To maxRow2 Step 3
        Range(Rows(j), Rows(j + 5)).Select
        Selection.Delete Shift:=x1Up
    Next j
    Range("A1").Select

    'Cut/paste the Steps and StepsAvg data
    Dim maxRow3 As Long
    maxRow3 = ActiveSheet.UsedRange.Rows.Count
    For k = 3 To maxRow Step 1
        Cells(k, 1).Select
        Selection.Cut
        Cells(k - 1, 2).Select
        ActiveSheet.Paste
        Cells(k + 1, 1).Select
        Selection.Cut
        Cells(k - 1, 3).Select
        ActiveSheet.Paste
        Range(Rows(k), Rows(k + 1)).Select
        Selection.Delete Shift:=x1Up
    Next k

【问题讨论】:

  • 为了让它更快,首先要做的是avoid using select
  • 谢谢,我已经开始改进代码了。您是否有替换“ActiveSheet.Paste”的建议? WAS:“范围(“A1:C1”)。选择...选择。剪切...范围(“B1”)。选择... ActiveSheet.Paste”尝试:“范围(“A1:C1”)。剪切... Range("B1").ActiveSheet.Paste" 但没有编译 有什么建议吗?
  • 您只想要值,还是也粘贴格式?
  • 对于初学者来说,.UsedRange 是不可靠的,有时是不可预测的。您是否没有一列总是将值降至 UsedRange 的底部?难道你没有类似标题行的东西,在 UsedRange 的末尾不会有任何空白吗?
  • 在后面的代码中'删除所有那些单数行我不清楚你是否知道你正在删除你用来计数的行之一或不是。通常,在删除行时,您会从下往上进行操作,这样您就不会越过在删除行后被替换的行。

标签: vba excel for-loop


【解决方案1】:

这里有几个指针:

1) 不要使用变量,除非您要多次使用它。 maxRowmaxRow2maxRow3 毫无意义。每个新变量都会增加您的应用程序使用的内存 (RAM) 量。在某些时候,VBA 的“垃圾收集器”会出现并进一步减慢您的代码速度。出于这个原因,使用大量变量是不好的做法,但减少这些不必要的变量的数量也可以提高可读性并减少混乱。


2) 定义循环变量时,无需为每个循环定义 3 个单独的变量。始终使用相同的。使用超过 1 个循环变量的唯一原因是您使用的是嵌套循环。例如

for i = 1 to 10
    for j = 2 to 5
        for k = 3 to 7
            debug.print i & "," & j & "," & k
        next k
    next j
next i

3) 你不需要选择一个单元格来操作它。以下语句是等价的:

cells(1,1).select
selection.value = "hello"

v.s.

cells(1,1).value = "hello"

虽然在这种情况下速度可以忽略不计,但在循环一个区域时,直接设置值比选择单元格然后设置值要快得多。


4) 要将值从一个单元格传输到另一个单元格,您不需要使用剪切和粘贴:

cells(1,1).cut
cells(2,1).select
activesheet.paste

与(几乎)相同

cells(2,1).value = cells(1,1).value  'doesn't copy formatting or formula! I assume this isn't required.

5) 删除整行数据时不需要 Shift(除非您想将数据向下移动)。所以rows(i).delete Shift:=x1Up可以简化为rows(i).delete


将所有这些放在一起就可以得到这个,在我看来它更具可读性并且速度也更快:

Dim i As Long

'Removes all those single number rows
For i = 2 To ActiveSheet.UsedRange.Rows.Count Step 3
    Rows(i).Delete
Next i

'Removes all those miles and min active data
For i = 5 To ActiveSheet.UsedRange.Rows.Count Step 3
    Range(Rows(i), Rows(i + 5)).Delete
Next i

'Cut/paste the Steps and StepsAvg data
For i = 3 To ActiveSheet.UsedRange.Rows.Count Step 1
    Cells(i - 1, 2).Value = Cells(i, 1).Value
    Cells(i - 1, 3).Value = Cells(i + 1, 1).Value
    Range(Rows(i), Rows(i + 1)).Delete
Next i

要提高速度,还有很多事情可以做。例如Application.ScreenUpdating=falseApplication.EnableEvents=False。更复杂的效率包括批量删除行而不是逐行删除。例如

'Removes all those single number rows
Dim rng as range: set rng = Rows(2)
For i = 5 To ActiveSheet.UsedRange.Rows.Count Step 3
    set rng = Application.union(rng,Rows(i))
Next i
rng.Delete

虽然代码看起来更复杂,但它也更快,因为您要批量处理更多行。另一种选择是使用数组而不是范围,这可能是最快的方法,但会复杂得多。

dim myArray as variant: myArray = Activesheet.UsedRange.Value
'do stuff with array
ActiveSheet.Clear
ActiveSheet.range(cells(1,1),cells(ubound(myArray,1),ubound(myArray,2)).value = myArray

但我离题了,前者对你来说可能已经足够快了。

【讨论】:

  • 您好心的先生,真是个天才!实施这些努力大大减少了处理时间。我还没有尝试过复杂的效率,但这已经产生了奇迹。
  • 复杂的效率并不是完全必要的。我确实测试了您的原始代码,并且确实花了很长时间。我感受到了你的痛苦……很高兴我能帮上忙!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-13
  • 1970-01-01
  • 2023-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多