Excel VBA UsedRange用于多个FOR循环,并且"重置"使宏更快

时间:2017-06-02 22:41:10

标签: excel vba excel-vba for-loop

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

  1. 删除编号为项目符号的行
  2. 删除了无关的数据(里程和分钟)
  3. 手动将其他数据集剪切/粘贴到各自的列中(步骤& stepavg)
  4. 它似乎运作良好,但我想优化这个过程。在运行宏时,问题在于我使用了" UsedRange"找出FOR LOOP 1(约800行)有多少行。在该循环期间,许多行被删除,因此它可以从800过滤到350.然后当执行FOR LOOP 2时,似乎UsedRange仍然引用800行,因此循环继续,从350过滤到65.最后使用FOR循环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
    

1 个答案:

答案 0 :(得分:1)

首先,这里有几点建议:

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

2)定义循环变量时,不需要为每个循环定义3个单独的变量。始终使用相同的一个。使用多个循环变量的唯一原因是您使用的是嵌套循环。 E.G。

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。更复杂的效率包括批量删除行而不是逐行删除。 E.G。

'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

但我离题前者很可能对你来说足够快。