web-dev-qa-db-fra.com

Comment supprimer des éléments de liste dans une boucle for en Python?

J'ai une liste

a = ["a", "b", "c", "d", "e"]

Je veux supprimer des éléments de cette liste dans une boucle comme ci-dessous:

for item in a:
    print item
    a.remove(item)

Mais ça ne marche pas. Que puis-je faire?

48
alwbtc

Vous n'êtes pas autorisé à supprimer des éléments de la liste lors d'une itération à l'aide d'une boucle for.

La meilleure façon de réécrire le code dépend de ce que vous essayez de faire.

Par exemple, votre code est équivalent à:

for item in a:
  print item
a[:] = []

Vous pouvez également utiliser une boucle while:

while a:
  print a.pop(0)

J'essaie de supprimer des éléments s'ils correspondent à une condition. Ensuite, je passe à l'élément suivant. 

Vous pouvez copier chaque élément qui ne correspond pas à la condition dans une deuxième liste:

result = []
for item in a:
  if condition is False:
    result.append(item)
a = result

Vous pouvez également utiliser filter ou une liste de compréhension et attribuer le résultat à a:

a = filter(lambda item:... , a)

ou

a = [item for item in a if ...]

... représente la condition à vérifier.

84
NPE

Parcourez une copie de la liste:

>>> a = ["a", "b", "c", "d", "e"]
>>> for item in a[:]:
    print item
    if item == "b":
        a.remove(item)

a
b
c
d
e
>>> print a
['a', 'c', 'd', 'e']
42
Alex L

Comme d'autres réponses l'ont déjà indiqué, la meilleure façon de procéder consiste à créer une nouvelle liste: vous pouvez soit effectuer une itération sur une copie, soit créer une liste contenant uniquement les éléments de votre choix et la réaffecter à la même variable. La différence entre celles-ci dépend de votre cas d'utilisation, car elles affectent différemment les autres variables de la liste d'origine (ou plutôt, la première les affecte, la seconde ne les affecte pas). 

Si une copie n'est pas une option pour une raison quelconque, vous avez une autre option qui repose sur une compréhension de la raison pour laquelle vous modifiez une liste, vous effectuez une itération. L'itération de liste fonctionne en gardant la trace d'un index, en l'incrémentant à chaque fois autour de la boucle jusqu'à la fin de la liste. Ainsi, si vous supprimez à (ou avant) l'indice actuel, tout ce qui se situe à partir de ce point jusqu'à la fin se décale d'un point vers la gauche. Mais l’itérateur ne le sait pas et saute effectivement l’élément suivant, car il se trouve maintenant dans le current index plutôt que dans le suivant. Cependant, supprimer les éléments qui se trouvent après l’index actuel n’affecte pas les choses. 

Cela implique que si vous parcourez la liste de haut en bas, si vous supprimez un élément de l'index actuel, tout ce qui se trouve à sa droite se décale à gauche, mais cela n'a pas la position actuelle, et vous vous déplacez à gauche - le prochain élément à gauche n'est pas affecté par le changement, de sorte que l'itérateur vous donne l'élément que vous attendez. 

TL; DR:

>>> a = list(range(5))
>>> for b in reversed(a):
    if b == 3:
        a.remove(b)
>>> a
[0, 1, 2, 4]

Cependant, faire une copie est généralement préférable pour rendre votre code facile à lire. Je mentionne cette possibilité uniquement dans un souci de complétude.

15
lvc

Pourquoi ne pas créer une nouvelle liste et ajouter les éléments souhaités à cette nouvelle liste? Vous ne pouvez pas supprimer d'éléments en parcourant une liste.

2
cobie
import copy

a = ["a", "b", "c", "d", "e"]

b = copy.copy(a)

for item in a:
    print item
    b.remove(item)
a = copy.copy(b)

Fonctionne: pour éviter de changer la liste sur laquelle vous effectuez une itération, vous faites une copie de a, parcourez-la et supprimez les éléments de b. Ensuite, vous copiez b (la copie modifiée) vers a.

1
user3848191

Probablement un peu tard pour répondre à cette question mais je viens de trouver ce fil et j'avais créé mon propre code auparavant ...

    list = [1,2,3,4,5]
    deleteList = []
    processNo = 0
    for item in list:
        if condition:
            print item
            deleteList.insert(0, processNo)
        processNo += 1

    if len(deleteList) > 0:
        for item in deleteList:
            del list[item]

Cela peut être long, mais semble bien fonctionner. Je crée une deuxième liste qui ne contient que des nombres liés à l'élément de la liste à supprimer. Notez que "insérer" insère le numéro d'élément de la liste à la position 0 et pousse le reste jusqu'à ce que, lors de la suppression des éléments, la liste soit supprimée du nombre le plus élevé au plus petit afin que la liste reste en séquence.

0
Todd Robards