66 votes

Comment supprimer un élément d'une liste python dans une boucle ?

Duplicata possible :
Supprimer des éléments d'une liste lors de l'itération en Python

J'essaie de supprimer un élément d'une liste en python :

x = ["ok", "jj", "uy", "poooo", "fren"]
for item in x:
    if len(item) != 2:
        print "length of %s is: %s" %(item, len(item))
        x.remove(item)

Mais ça n'enlève pas "fren" article. Des idées ?

109voto

Sven Marnach Points 133943

Vous ne pouvez pas supprimer des éléments d'une liste tout en la parcourant. Il est beaucoup plus facile de construire une nouvelle liste à partir de l'ancienne :

y = [s for s in x if len(s) == 2]

50voto

gurney alex Points 4837

Les réponses de hymloth et sven fonctionnent, mais elles ne modifient pas la liste (elles en créent une nouvelle). Si vous avez besoin de modifier l'objet, vous devez l'assigner à une tranche :

x[:] = [value for value in x if len(value)==2]

Cependant, pour les grandes listes dans lesquelles vous devez supprimer quelques éléments, cette méthode est gourmande en mémoire, mais elle s'exécute en O(n).

La réponse de glglgl souffre d'une complexité O(n²), car list.remove est O(n).

Selon la structure de vos données, vous préférerez peut-être noter les index des éléments à supprimer et utiliser la fonction del le travail clé à supprimer par index :

to_remove = [i for i, val in enumerate(x) if len(val)==2]
for index in reversed(to_remove): # start at the end to avoid recomputing offsets
    del x[index]

Maintenant del x[i] est également O(n) car il faut copier tous les éléments après l'indice i (une liste est un vecteur), vous devrez donc la tester avec vos données. Néanmoins, cela devrait être plus rapide que d'utiliser remove parce que vous ne payez pas pour le coût de l'étape de recherche de la suppression, et que le coût de l'étape de copie est le même dans les deux cas.

[edit] Très belle version in-place, O(n) avec des exigences de mémoire limitées, avec l'aimable autorisation de @Sven Marnach . Il utilise itertools.compress qui a été introduit dans python 2.7 :

from itertools import compress

selectors = (len(s) == 2 for s in x)
for i, s in enumerate(compress(x, selectors)): # enumerate elements of length 2
    x[i] = s # move found element to beginning of the list, without resizing
del x[i+1:]  # trim the end of the list

7voto

hymloth Points 2832
x = [i for i in x if len(i)==2]

3voto

glglgl Points 35668

Cela vient du fait que lors de la suppression, l'itération saute un élément car elle a l'impression de ne travailler que sur l'index.

La solution de rechange pourrait être :

x = ["ok", "jj", "uy", "poooo", "fren"]
for item in x[:]: # make a copy of x
    if len(item) != 2:
        print "length of %s is: %s" %(item, len(item))
        x.remove(item)

2voto

Austin Marshall Points 1104

L'approche de la compréhension des listes déjà mentionnée est probablement votre meilleure option. Mais si vous voulez absolument le faire in-place (par exemple si x est très grande), voici une solution :

x = ["ok", "jj", "uy", "poooo", "fren"]
index=0
while index < len(x):
    if len(x[index]) != 2:
        print "length of %s is: %s" %(x[index], len(x[index]))
        del x[index]
        continue
    index+=1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X