EDIT Summary and reccomendations
Using a for each cell in range
construct is not in itself slow. What is slow is repeated access to Excel in the loop (be it reading or writing cell values, format etc, inserting/deleting rows etc).
What is too slow depends entierly on your needs. A Sub that takes minutes to run might be OK if only used rarely, but another that takes 10s might be too slow if run frequently.
So, some general advice:
for index = max to min step -1
)value
, you are stuck with cell referenceseg (not tested!)
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
Original post
Conventional wisdom says that looping through cells is bad and looping through a variant array is good. I too have been an advocate of this for some time. Your question got me thinking, so I did some short tests with suprising (to me anyway) results:
test data set: a simple list in cells A1
.. A1000000
(thats 1,000,000 rows)
Test case 1: loop an array
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, "#,###")
Result:
Array Time = 0.249 sec
Array Count = 1,000,001
Test Case 2: loop the range
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, "#,###")
Result:
Range Time = 0.296 sec
Range Count = 1,000,000
So,looping an array is faster but only by 19% - much less than I expected.
Test 3: loop an array with a cell reference
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, "#,###")
Result:
Array Time = 5.897 sec
Array Count = 1,000,000
Test case 4: loop range with a cell reference
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, "#,###")
Result:
Range Time = 2.356 sec
Range Count = 1,000,000
So event with a single simple cell reference, the loop is an order of magnitude slower, and whats more, the range loop is twice as fast!
So, conclusion is what matters most is what you do inside the loop, and if speed really matters, test all the options
FWIW, tested on Excel 2010 32 bit, Win7 64 bit All tests with
ScreenUpdating
off,Calulation
manual, Events
disabled.