Comment obtenir l'index d'un élément lors du parcours d'un tableau en Swift ? Décryptage d'une question populaire
\n\nImaginez : vous codez en Swift et vous souhaitez non seulement parcourir un tableau, mais aussi connaître la position de chaque élément. Que vous ayez besoin de modifier des éléments par index, de comparer des valeurs adjacentes ou simplement d'afficher une liste numérotée, le problème est le même. La question "How to iterate a loop with index and element in Swift" a recueilli des milliers de vues sur Stack Overflow. Preuve que ce sujet préoccupe beaucoup de monde.
\n\nDans cet article, nous ne nous contenterons pas de donner une réponse toute faite. Nous allons regarder sous le capot : analyser les différentes méthodes existantes, laquelle est la plus rapide, laquelle est la plus sûre, et pourquoi l'une d'elles — enumerated() — est devenue le standard de facto. C'est parti !
Problème : pourquoi le simple for-in ne convient-il pas ?
\n\nSupposons que vous ayez un tableau de chaînes :
\n\nlet fruits = ["Pomme", "Banane", "Cerise", "Melon"]\n\nLa méthode la plus évidente est for-in :
for fruit in fruits {\n print(fruit)\n}\n\nCela affichera les noms des fruits. Mais que faire si vous avez besoin de connaître l'index ? Par exemple : "1. Pomme, 2. Banane..." ? Le simple for-in ne fournit pas d'index. Il faut alors bricoler des solutions de fortune :
var index = 0\nfor fruit in fruits {\n print("\\(index). \\(fruit)")\n index += 1\n}\n\nÇa marche ? Oui. C'est élégant ? Non. Et si le tableau est vide ? Et si vous oubliez accidentellement d'incrémenter index ? Bienvenue dans le monde des bugs. Swift propose des solutions plus élégantes.
Méthode n°1 : La classique — la méthode enumerated()
\n\nC'est la méthode la plus populaire et recommandée. La méthode enumerated() retourne une séquence de tuples (offset: Int, element: Element). Voyons comment cela fonctionne :
for (index, fruit) in fruits.enumerated() {\n print("\\(index + 1). \\(fruit)")\n}\n\nAffichage :
\n1. Pomme\n2. Banane\n3. Cerise\n4. Melon\n\nQue se passe-t-il sous le capot ?
\n\nenumerated() ne crée pas un nouveau tableau. Il retourne une séquence paresseuse de type EnumeratedSequence. Cela signifie que les éléments ne sont pas copiés dans une nouvelle structure de données — ils sont "encapsulés" à la volée. À chaque accès à l'élément suivant, la séquence incrémente simplement le compteur et retourne un tuple. C'est très efficace en termes de mémoire, surtout pour les grandes collections.
Un détail important : offset commence toujours à 0. Si vous avez besoin d'un index commençant à 1 (comme dans la numérotation de listes), ajoutez simplement un. Swift ne le fait pas pour vous — c'est une décision délibérée des développeurs du langage pour maintenir une cohérence avec l'indexation des tableaux.
enumerated() avec forEach
\n\nLa méthode forEach supporte également enumerated() :
fruits.enumerated().forEach { (index, fruit) in\n print("\\(index). \\(fruit)")\n}\n\nLa différence entre for-in et forEach est importante : à l'intérieur de forEach, on ne peut pas utiliser break ou continue. Si vous devez sortir prématurément de la boucle — utilisez for-in.
Méthode n°2 : Indexation via une plage (Range)
\n\nUne méthode ancienne, mais encore rencontrée — itérer sur les index :
\n\nfor index in 0..<fruits.count {\n print("\\(index). \\(fruits[index])")\n}\n\nÇa semble simple. Mais il y a des pièges :
\n\n- \n
- Sécurité : Si le tableau change pendant l'itération (par exemple, dans du code multithreadé),
fruits.countpeut devenir obsolète, et vous sortirez des limites du tableau. \n - Lisibilité : Le code semble plus "bas niveau". Les autres développeurs perdront une seconde supplémentaire pour comprendre ce que vous faites. \n
- Performance : L'accès par index
fruits[index]est une opération O(1) pour les tableaux, mais pour d'autres