🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA For Each dans Excel — parcourir une collection sans toucher à l'indice (et les pièges qu'il cache)

|

VBA For Each dans Excel — parcourir une collection sans toucher à l'indice (et les pièges qu'il cache)

TL;DRFor Each item In collection parcourt chaque membre d'une collection et vous les remet un à un — sans compteur, sans .Count, sans décalage d'une unité. Utilisez-le quand vous avez une collection (un Range, les Worksheets, un tableau) et que vous voulez toucher chaque élément. Ne revenez à For i = 1 To N que lorsque vous avez besoin de l'indice lui-même : pour parcourir à l'envers, pour sauter avec Step, ou pour supprimer des éléments au fil de l'eau. Trois règles l'empêchent de vous trahir : la variable de boucle doit être un objet ou un Variant, parcourir un tableau est en lecture seule, et vous ne devez jamais retirer d'éléments de la collection que vous parcourez.

Dim cell As Range
Dim total As Double

For Each cell In Sheets("Data").Range("B2:B11")
    total = total + cell.Value      ' VBA vous remet chaque cellule à son tour
Next cell

Debug.Print total                   ' pas de i, pas de .Count, aucune borne à rater

La plupart des boucles des vraies macros disent au fond la même chose : « pour chaque cellule de cette plage… », « pour chaque feuille de ce classeur… », « pour chaque nom de cette liste… ». For Each, c'est VBA qui vous laisse écrire cette phrase presque littéralement. Le For i = 1 To N à compteur peut exprimer la même idée, mais il vous laisse gérer vous-même l'indice — valeur de départ, valeur de fin, le .Count, le décalage d'une unité. For Each vous décharge de cette comptabilité. Le revers, c'est qu'il vous retire l'indice entièrement, et quelques opérations en ont réellement besoin.

Ce que vous allez apprendre

  • Le modèle mental — For Each parcourt l'appartenance, pas les positions
  • Pourquoi la variable de boucle doit être un Range, un Worksheet ou un Variant — jamais un Long
  • Le piège de la lecture seule : affecter la variable de boucle d'un tableau ne fait rien
  • Pourquoi supprimer à l'intérieur d'un For Each corrompt silencieusement le parcours — et que faire à la place
  • Une règle claire pour choisir For Each ou revenir à For…Next

Le modèle mental : For Each parcourt l'appartenance, pas les positions

Une boucle à compteur pense en positions : « va à la case 1, puis à la case 2, puis à la case 3 ». For Each pense en appartenance : « donne-moi chaque chose qui appartient à ce groupe, dans l'ordre où le groupe les conserve ». Vous ne dites jamais se trouve un élément ; vous le recevez, tout simplement.

Ce basculement explique pourquoi For Each est plus court et, sur de grandes plages, légèrement plus rapide. Avec Cells(i, 1), VBA doit calculer l'adresse et résoudre la cellule à chaque itération. Avec For Each cell In rng, l'énumérateur intégré de la collection vous remet à chaque fois un objet Range déjà résolu — aucun calcul. Vous échangez le numéro d'indice contre un parcours plus propre et plus rapide. Tout ce qui suit découle de l'absence de cet indice.

La règle qui décide du type de la variable de boucle : objet ou Variant, jamais Long

C'est la première chose qui fait trébucher, car c'est l'inverse d'une boucle à compteur. Dans For i = 1 To 10, i est un Long. Dans un For Each, la variable de boucle reçoit un élément entier de la collection : elle doit donc pouvoir le contenir :

' Plage de cellules -> l'élément est un Range
Dim cell As Range
For Each cell In Range("A1:A10")
    cell.Value = cell.Value * 2
Next cell

' Worksheets -> l'élément est un Worksheet
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
    Debug.Print ws.Name
Next ws

Déclarez Dim cell As Long pour parcourir une plage et VBA lève « Objet requis » (erreur 424) à l'instant où il tente de fourrer un Range dans un nombre. La règle : le type de la variable de boucle doit correspondre au genre de chose que contient la collectionRange pour des cellules, Worksheet pour des feuilles, Workbook pour des classeurs ouverts.

Il existe une exception, et c'est celle qu'on oublie : les tableaux. Un tableau VBA peut tout contenir, si bien que le compilateur ne peut pas connaître le type d'élément à l'avance. Parcourir un tableau avec For Each exige un Variant :

Dim names As Variant
names = Array("Alice", "Bob", "Carol")

Dim n As Variant          ' OBLIGATOIREMENT un Variant pour parcourir un tableau
For Each n In names
    Debug.Print n
Next n

Utilisez Dim n As String ici et vous obtiendrez une erreur d'incompatibilité de type. Dans le doute sur un tableau, la variable de boucle est un Variant.

La règle qui piège tout le monde une fois : parcourir un tableau est en lecture seule

Voici un bug qui semble devoir fonctionner et n'en fait rien :

Dim nums As Variant
nums = Array(1, 2, 3)

Dim x As Variant
For Each x In nums
    x = x * 10            ' on croit multiplier chaque élément...
Next x

Debug.Print nums(0), nums(1), nums(2)   ' -> 1  2  3   (INCHANGÉ)

Vous avez multiplié x, pas le tableau. Quand For Each parcourt un tableau, la variable de boucle est une copie de l'élément, pas une prise en direct sur lui. Affecter x modifie la copie et la jette à l'itération suivante. Le tableau ne bouge jamais.

C'est la chose la plus importante à savoir sur For Each, car elle échoue en silence — aucune erreur, juste des données périmées. La solution est de revenir à une boucle à compteur, qui atteint le véritable élément par son indice :

Dim i As Long
For i = LBound(nums) To UBound(nums)
    nums(i) = nums(i) * 10     ' CECI modifie réellement le tableau
Next i

Notez l'asymétrie : parcourir un Range avec For Each est modifiable (cell.Value = … traverse l'objet Range jusqu'à la vraie cellule), car cell est une référence d'objet, pas une copie. Ce sont spécifiquement les tableaux — et les éléments de type valeur — qui sont en lecture seule sous For Each. Si votre boucle doit réécrire le contenu d'un tableau, utilisez For i = LBound To UBound.

La règle qu'on apprend à ses dépens : ne jamais supprimer de la collection que vous parcourez

For Each s'appuie sur l'énumérateur de la collection, et cet énumérateur suppose que la collection ne change pas de forme sous ses pieds. Retirez un élément en plein parcours et l'énumérateur perd sa place — il saute des éléments, ou lève une erreur, et il ne vous dit jamais lesquels.

' CASSÉ — supprimer décale la collection sous l'énumérateur
Dim sh As Worksheet
For Each sh In ThisWorkbook.Worksheets
    If sh.Name Like "Temp*" Then sh.Delete   ' saute des feuilles, imprévisible
Next sh

Le même piège vous attend quand vous supprimez des lignes de feuille, retirez des éléments d'une Collection ou enlevez des clés d'un Dictionary à l'intérieur d'un For Each. La règle est absolue : si la boucle modifie l'appartenance de la collection, n'utilisez pas For Each. Parcourez-la plutôt avec un compteur à l'envers, de sorte que retirer un élément ne perturbe jamais les indices que vous n'avez pas encore visités :

' CORRECT — décompter pour que les suppressions ne décalent pas le reste
Dim i As Long
For i = ThisWorkbook.Worksheets.Count To 1 Step -1
    With ThisWorkbook.Worksheets(i)
        If .Name Like "Temp*" Then .Delete
    End With
Next i

C'est la même discipline de parcours inversé que vous employez pour supprimer des lignes de tableur sans risque — voyez le motif Step -1 dans VBA For Loop. L'idée directrice : For Each sert à lire et modifier des éléments en place ; une boucle à compteur décroissante sert à en ajouter ou en retirer.

Quand choisir For Each plutôt que For…Next

Aucune des deux boucles n'est « meilleure » — elles répondent à des questions différentes. Choisissez selon ce que la tâche exige de l'indice :

  • Utilisez For Each quand vous avez une collection et voulez toucher chaque membre dans son ordre naturel : sommer une plage, mettre en forme chaque cellule, afficher le nom de chaque feuille, traiter chaque élément une fois. Plus lisible, aucune borne à rater, et plus rapide sur de grandes plages.
  • Utilisez For i = 1 To N quand vous avez besoin de l'indice comme valeur — pour écrire dans la ligne i, pour parcourir à l'envers (Step -1), pour sauter (Step 2), pour comparer l'élément i avec l'élément i+1, ou pour supprimer au fil de l'eau. C'est aussi le seul moyen modifiable de réécrire les éléments d'un tableau.

Un indice révélateur : si vous vous surprenez à appeler .Count et à fabriquer votre propre i juste pour atteindre collection(i), c'est probablement For Each que vous vouliez. Si vous cherchez l'élément avant ou après l'élément courant, ou si vous retirez des éléments, il vous faut le compteur.

Comment ExcelMaster aide

Choisir la boucle, typer correctement la variable de boucle, se rappeler que les tableaux sont en lecture seule et que les suppressions doivent se faire à l'envers — c'est exactement le genre de jugement mécanique qui se dresse entre « je sais ce que je veux » et « la macro le fait correctement ».

ExcelMaster vous laisse énoncer l'objectif à la place. Dites « dans la feuille Commandes, surligne chaque ligne dont le statut est En retard » ou « supprime chaque feuille dont le nom commence par Temp », et il écrit et exécute la logique — en choisissant For Each là où un simple parcours convient et un compteur décroissant là où des éléments sont retirés, pour que le bug d'ordre de suppression ne se produise jamais. Quand vous écrivez vraiment à la main une macro planifiée, c'est encore vous qui choisirez la boucle. Pour la tâche quotidienne « fais juste ça sur les données d'aujourd'hui », décrire le résultat vaut mieux que réussir à la main chaque règle d'énumérateur.

Questions fréquentes

Quelle est la différence entre For Each et For…Next en VBA ?

For Each parcourt une collection par appartenance — il vous remet chaque élément dans l'ordre naturel de la collection et vous ne gérez jamais d'indice. For i = 1 To N est à compteur — vous contrôlez l'indice, donc vous pouvez parcourir à l'envers avec Step -1, sauter avec Step 2, ou atteindre l'élément i+1. Utilisez For Each pour un simple parcours d'un Range, des Worksheets ou d'un tableau ; utilisez For…Next quand il vous faut l'indice, que vous voulez supprimer des éléments, ou que vous devez réécrire les éléments d'un tableau.

Pourquoi ai-je « Objet requis » (erreur 424) dans une boucle For Each ?

Presque toujours parce que la variable de boucle est déclarée avec le mauvais type — souvent un Long ou un String alors que la collection contient des objets. For Each cell In Range(...) réclame Dim cell As Range, et For Each ws In Worksheets réclame Dim ws As Worksheet. Si vous parcourez un tableau VBA, la variable de boucle doit être un Variant.

Puis-je modifier les valeurs d'un tableau dans une boucle For Each ?

Non. Quand For Each parcourt un tableau, la variable de boucle est une copie de chaque élément, si bien que l'affecter modifie la copie, pas le tableau — sans aucune erreur. Pour modifier le tableau, utilisez une boucle à compteur : For i = LBound(arr) To UBound(arr) et affectez arr(i). Parcourir un Range avec For Each est modifiable, car la variable de boucle est une référence d'objet en direct vers la cellule.

Comment parcourir chaque cellule d'une plage avec For Each ?

Déclarez la variable de boucle en Range et parcourez directement la plage : For Each cell In Range("A1:B10"). VBA parcourt les cellules ligne par ligne. Pour un grand bloc, c'est plus rapide que des boucles Cells(i, j) imbriquées, mais l'approche la plus rapide de toutes est de lire la plage dans un tableau en une seule fois (arr = Range("A1:B10").Value) et de parcourir le tableau — voyez VBA Array.

Pourquoi supprimer des lignes ou des feuilles dans un For Each en saute-t-il certaines ?

Parce que For Each s'appuie sur un énumérateur qui suppose que l'appartenance de la collection ne change pas pendant le parcours. Supprimer un élément décale tout ce qui le suit, et l'énumérateur perd sa place — sautant des éléments en silence. Ne supprimez jamais à l'intérieur d'un For Each. Utilisez une boucle à compteur qui décompte vers le bas (For i = .Count To 1 Step -1) pour que les retraits ne perturbent pas les éléments que vous n'avez pas encore atteints.

Testé dans

Testé avec : Excel 365 (Windows 11), VBA 7.1 — dernière vérification le 01/08/2026.

Guides associés : VBA For Loop · VBA Collection · VBA With · VBA Array · VBA Dictionary