在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议:
- 首先保持简单。 如果结果太慢,您的需求,然后优化
- 着重优化循环的内容
- 不要只是假设一个循环是需要的。 有一些替代品
- 如果你需要在循环中使用单元格值(很多),请将它们加载到循环外部的variables数组中。
- 避免插入复杂性的一个好方法就是从下往上循环范围
(for index = max to min step -1
) - 如果你不能这样做,你的'插入一行'不是太多,考虑每次插入后重新加载数组
- 如果您需要访问单元格属性而不是
value
,则您将被禁用单元格引用 - 要删除多行,请考虑在循环中构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)
=>即使你正在通过相同的构造,你会发现一个巨大的差异。