Je sais que VBA dans Excel n'est pas la chose la plus rapide - mais j'ai besoin du moyen le plus efficace (c'est-à-dire le plus rapide) pour parcourir un large échantillon de lignes.
Actuellement, j'ai:
For Each c In Range("$A$2:$A$" & Cells(Rows.count, "A").End(xlUp).row
' do stuff
Next c
Le 'do stuff' comprend l'insertion d'une ligne ici et là (donc je dois garder la recherche dynamique de la plage.)
Des idées (en regardant 10 000 lignes +)?
EDIT J'utilise déjà
Application.ScreenUpdating = False
Application.Calculation = xlManual
Si vous parcourez simplement 10 000 lignes dans la colonne A, puis videz la ligne dans un tableau de variantes, puis parcourez-le.
Vous pouvez ensuite soit ajouter les éléments à un nouveau tableau (tout en ajoutant des lignes si nécessaire) et utiliser Transpose () pour placer le tableau sur votre plage en un seul mouvement, soit utiliser votre variable itérateur pour suivre la ligne sur laquelle vous vous trouvez et ajouter lignes de cette faç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
Voici un exemple de la façon dont vous pouvez ajouter des lignes après avoir évalué chaque cellule. Cet exemple insère juste une ligne après chaque ligne qui a le mot "foo" dans la colonne A. Pas que le "+2" soit ajouté à la variable i pendant l'insertion puisque nous commençons sur A2. Ce serait +1 si nous commencions notre tableau avec A1.
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
MODIFIER Résumé et recommandations
Utilisant un for each cell in range
la construction n'est pas en elle-même lente. Ce qui est lent est un accès répété à Excel dans la boucle (que ce soit la lecture ou l'écriture de valeurs de cellule, le format, etc., l'insertion/la suppression de lignes, etc.).
Ce qui est trop lent dépend entièrement de vos besoins. Un Sub qui prend quelques minutes à fonctionner peut être OK s'il n'est utilisé que rarement, mais un autre qui prend 10 secondes peut être trop lent s'il est exécuté fréquemment.
Donc, quelques conseils généraux:
for index = max to min step -1
)value
, vous êtes bloqué avec des références de cellulepar exemple (non testé!)
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
Message d'origine
La sagesse conventionnelle dit que la boucle à travers les cellules est mauvaise et la boucle à travers un tableau de variantes est bonne . Moi aussi, je défends cela depuis un certain temps. Votre question m'a fait réfléchir, j'ai donc fait quelques tests courts avec des résultats surprenants (pour moi en tout cas):
ensemble de données de test: une simple liste dans les cellules A1
.. A1000000
(c'est 1 000 000 de lignes)
Cas de test 1: boucle un tableau
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, "#,###")
Résultat:
Array Time = 0.249 sec
Array Count = 1,000,001
Cas de test 2: boucle la gamme
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, "#,###")
Résultat:
Range Time = 0.296 sec
Range Count = 1,000,000
Ainsi, boucler un tableau est plus rapide mais seulement de 19% - beaucoup moins que ce à quoi je m'attendais.
Test 3: boucle un tableau avec une référence de cellule
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, "#,###")
Résultat:
Array Time = 5.897 sec
Array Count = 1,000,000
Cas de test 4: plage de boucle avec une référence de cellule
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, "#,###")
Résultat:
Range Time = 2.356 sec
Range Count = 1,000,000
Donc, événement avec une seule référence de cellule simple, la boucle est un ordre de grandeur plus lent, et de plus, la boucle de plage est deux fois plus rapide!
Donc, la conclusion est ce qui compte le plus, c'est ce que vous faites à l'intérieur de la boucle , et si la vitesse compte vraiment, testez toutes les options
FWIW, testé sur Excel 2010 32 bits, Win7 64 bits Tous les tests avec
ScreenUpdating
off,Calulation
manuel,Events
désactivé.Pour Chacun est beaucoup plus rapide que pour I = 1 à X, pour une raison quelconque. Essayez simplement de parcourir le même dictionnaire,
une fois avec pour chaque Dkey dans dDict,
et une fois avec pour Dkey = lbound (dDict.keys) à ubound (dDict.keys)
=> Vous remarquerez une énorme différence, même si vous passez par la même construction.