我知道Excel中的VBA并不是最快的东西 - 但我需要最有效(即最快)的方法来循环遍历大量的行。
目前我有:
For Each c In Range("$A$2:$A$" & Cells(Rows.count, "A").End(xlUp).row
' do stuff
Next c
'do stuff'包括在这里和那里插入一行(所以我需要保持范围的动态查找。)
任何想法(看10,000行+)?
EDIT 我已经在使用
了Application.ScreenUpdating = False
Application.Calculation = xlManual
答案 0 :(得分:36)
如果您只是循环遍历A列中的10k行,则将该行转储到变量数组中,然后遍历该行。
然后,您可以将元素添加到新数组(在需要时添加行),并使用Transpose()将数组一次性放入您的范围,或者您可以使用迭代器变量来跟踪您是哪一行on并以这种方式添加行。
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”添加到变量i。如果我们用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
答案 1 :(得分:19)
编辑摘要和推荐
使用for each cell in range
构造本身不是 慢。什么 慢是在循环中重复访问Excel(无论是读取或写入单元格值,格式等,插入/删除行等)。
什么太慢取决于你的需求。一个需要几分钟才能运行的Sub可能只是很少使用,但是如果经常运行则需要10秒的另一个可能太慢了。
所以,一些一般建议:
for index = max to min step -1
)value
以外的单元格属性,则会遇到单元格引用例如(未经测试!)
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
原帖
传统观点认为循环遍历单元格错误并且通过变量数组循环 good 。一段时间以来,我也一直是这方面的倡导者。你的问题让我想到了,所以我做了一些简短的测试,结果令人惊讶(对我来说)结果:
测试数据集:单元格A1
中的简单列表.. A1000000
(即1,000,000行)
测试用例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
测试案例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% - 远低于我的预期。
测试3:使用单元格引用循环数组
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
测试用例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
使用单个简单单元格引用的事件,循环速度慢一个数量级,而且更多,范围循环的速度是其两倍!
所以,结论是最重要的是你在循环中做什么,如果速度真的很重要,那么测试所有选项
FWIW,在Excel 2010 32位,Win7 64位上测试 所有测试
ScreenUpdating
关闭,Calulation
手册,Events
已停用。 答案 2 :(得分:1)
由于某种原因,每个比I = 1到X要快得多。试着通过相同的字典,
dDict中的每个Dkey,
一次用于Dkey = lbound(dDict.keys)到ubound(dDict.keys)
=>即使您正在使用相同的构造,您也会发现巨大的差异。