在VBA(excel)中循环行的最有效/最快捷的方法是什么?

我知道Excel中的VBA不是最快的东西 – 但是我需要最有效的(即最快的)方法来循环大量样本行。

目前我有:

For Each c In Range("$A$2:$A$" & Cells(Rows.count, "A").End(xlUp).row ' do stuff Next c 

“做的东西”包括在这里和那里插入一行(所以我需要保持范围的dynamic查找。)

任何想法(看10,000行+)?

编辑我已经在使用

 Application.ScreenUpdating = False Application.Calculation = xlManual 

如果您只是循环遍历A列中的10k行,则将该行转储到variables数组中,然后循环遍历该行。

然后,您可以将这些元素添加到新的数组(在需要的时候添加行),并使用Transpose()将数组放到您的范围内,或者使用您的迭代器variables来跟踪您所在的行并添加这样的行。

 Dim i As Long Dim varray As Variant varray = Range("A2:A" & Cells(Rows.Count, "A").End(xlUp).Row).Value For i = 1 To UBound(varray, 1) ' do stuff to varray(i, 1) Next 

这是一个如何在评估每个单元格后添加行的例子。 这个例子只是在列A中包含单词“foo”的每一行之后插入一行。不是因为我们是在A2上开始的,插入期间“+2”被添加到variablesi中。 如果我们用A1开始我们的数组,那么它将是+1。

 Sub test() Dim varray As Variant Dim i As Long varray = Range("A2:A10").Value 'must step back or it'll be infinite loop For i = UBound(varray, 1) To LBound(varray, 1) Step -1 'do your logic and evaluation here If varray(i, 1) = "foo" Then 'not how to offset the i variable Range("A" & i + 2).EntireRow.Insert End If Next End Sub 

编辑总结和reccomendations

使用for each cell in range构造中的for each cell in range 本身并不慢。 什么慢循环访问Excel(无论是读取或写入单元格值,格式等,插入/删除行等)。

什么太慢取决于你的需要。 需要花费数分钟才能运行的Sub可能很less使用,但如果运行频繁,则需要花费10s的Sub可能会太慢。

所以,一些一般的build议:

  1. 首先保持简单。 如果结果太慢,您的需求,然后优化
  2. 着重优化循环的内容
  3. 不要只是假设一个循环是需要的。 有一些替代品
  4. 如果你需要在循环中使用单元格值(很多),请将它们加载到循环外部的variables数组中。
  5. 避免插入复杂性的一个好方法就是从下往上循环范围
    for index = max to min step -1
  6. 如果你不能这样做,你的'插入一行'不是太多,考虑每次插入后重新加载数组
  7. 如果您需要访问单元格属性而不是value ,则您将被禁用单元格引用
  8. 要删除多行,请考虑在循环中构build一个范围引用到多区域范围,然后在循环之后一次删除该范围

例如(未testing!)

 Dim rngToDelete as range for each rw in rng.rows if need to delete rw then if rngToDelete is nothing then set rngToDelete = rw else set rngToDelete = Union(rngToDelete, rw) end if endif next rngToDelete.EntireRow.Delete 

原帖

传统观点认为,循环遍历单元格是不好的 ,循环遍历variables数组是很好的 。 一段时间以来,我也一直是这方面的倡导者。 你的问题让我想到了,所以我做了一些短暂的testing(对我来说)结果:

testing数据集:单元格A1 .. A1000000 (即1,000,000行)的简单列表

testing用例1:循环一个数组

 Dim v As Variant Dim n As Long T1 = GetTickCount Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells v = r For n = LBound(v, 1) To UBound(v, 1) 'i = i + 1 'i = r.Cells(n, 1).Value 'i + 1 Next Debug.Print "Array Time = " & (GetTickCount - T1) / 1000# Debug.Print "Array Count = " & Format(n, "#,###") 

结果:

 Array Time = 0.249 sec Array Count = 1,000,001 

testing用例2:循环范围

 T1 = GetTickCount Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells For Each c In r Next c Debug.Print "Range Time = " & (GetTickCount - T1) / 1000# Debug.Print "Range Count = " & Format(r.Cells.Count, "#,###") 

结果:

 Range Time = 0.296 sec Range Count = 1,000,000 

所以,循环数组更快,但只有19% – 比我预期的要less得多。

testing3:用单元格引用循环一个数组

 T1 = GetTickCount Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells v = r For n = LBound(v, 1) To UBound(v, 1) i = r.Cells(n, 1).Value Next Debug.Print "Array Time = " & (GetTickCount - T1) / 1000# & " sec" Debug.Print "Array Count = " & Format(i, "#,###") 

结果:

 Array Time = 5.897 sec Array Count = 1,000,000 

testing案例4:带单元格引用的循环范围

 T1 = GetTickCount Set r = Range("$A$1", Cells(Rows.Count, "A").End(xlUp)).Cells For Each c In r i = c.Value Next c Debug.Print "Range Time = " & (GetTickCount - T1) / 1000# & " sec" Debug.Print "Range Count = " & Format(r.Cells.Count, "#,###") 

结果:

 Range Time = 2.356 sec Range Count = 1,000,000 

所以事件只有一个简单的单元格引用,循环的速度要慢一个数量级,而且范围循环的速度要快一倍!

所以,结论是最重要的是你在循环内做什么,如果速度真的很重要,testing所有的选项

FWIW,Excel 2010 32位testing,Win7 64位所有testing

  • ScreenUpdating
  • Calulation手册,
  • Events禁用。

因为某种原因,对于每一个都比从I = 1到X要快得多。 只要尝试通过相同的字典,


一旦在dDict中的每个Dkey,


并用Dkey = lbound(dDict.keys)到ubound(dDict.keys)

=>即使你正在通过相同的构造,你会发现一个巨大的差异。