编辑总结和建议
使用for each cell in range 构造本身并不慢。 慢的是在循环中重复访问 Excel(读取或写入单元格值、格式等、插入/删除行等)。
什么太慢完全取决于您的需求。一个需要几分钟才能运行的 Sub 如果很少使用可能还可以,但另一个需要 10 秒的 Sub 如果频繁运行可能会太慢。
所以,一些一般性建议:
- 首先保持简单。如果结果太慢,无法满足您的需求,请进行优化
- 专注于循环内容的优化
- 不要只是假设需要循环。有时会有其他选择
- 如果您需要在循环内(大量)使用单元格值,请将它们加载到循环外的变量数组中。
- 避免插入复杂性的一个好方法是从下往上循环范围
(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
原帖
传统观点认为循环遍历单元格是不好的,而遍历一个变体数组是好的。一段时间以来,我也一直倡导这一点。你的问题让我思考,所以我做了一些简短的测试,结果令人惊讶(无论如何对我来说):
测试数据集:单元格中的简单列表 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 已禁用。