Suppression d'un élément de la liste - pendant l'itération - quel est le problème avec cet idiome?
Comme une expérience, j'ai fait ça:
letters=['a','b','c','d','e','f','g','h','i','j','k','l']
for i in letters:
letters.remove(i)
print letters
La dernière impression montre que tous les éléments ont été supprimés ? (tous les autres).
IDLE 2.6.2
>>> ================================ RESTART ================================
>>>
['b', 'd', 'f', 'h', 'j', 'l']
>>>
Quelle est l'explication pour cela ? Comment cela pourrait-il être ré-écrit pour supprimer chaque élément ?
source d'informationauteur monojohnny
Vous devez vous connecter pour publier un commentaire.
Quelques réponses pour expliquer pourquoi cela se produit et certaines expliquer ce que vous devriez vous avez fait. Je vais sans vergogne mettre les morceaux ensemble.
Quelle est la raison?
Parce que le langage Python est conçu pour traiter ce cas d'utilisation différente. La documentation indique clairement:
Accent de la mine. Voir la page liée, la documentation est protégée par copyright et tous les droits sont réservés.
Que vous pouvez facilement comprendre pourquoi vous l'avez obtenu ce que vous avez, mais c'est essentiellement un comportement indéfini qui permettent de changer facilement sans l'avertissement de construire de construire. Il suffit de ne pas le faire.
C'est comme vous vous demandez pourquoi
i += i++ + ++i
est-ce que l'enfer c'est que la ligne ne sur votre architecture sur votre build spécifique de votre compilateur pour votre langue -- y compris mais non limité à bousiller votre ordinateur et prise de démons voler hors de votre nez 🙂Comment cela pourrait-il être ré-écrit pour supprimer chaque élément?
del letters[:]
(si vous avez besoin de changer toutes les références à cet objet)letters[:] = []
(si vous avez besoin de changer toutes les références à cet objet)letters = []
(si vous voulez juste travailler avec un nouvel objet)Peut-être vous souhaitez supprimer certains éléments en fonction d'une condition? Dans ce cas, vous devez effectuer une itération sur une copie de la liste. Le moyen le plus facile de faire une copie est à rendre une tranche contenant l'ensemble de la liste avec la
[:]
syntaxe, comme suit:Si votre chèque n'est pas particulièrement compliqué, vous pouvez (et devriez) filtre à la place:
Vous ne pouvez pas parcourir une liste et de les transformer dans le même temps, au lieu itérer sur une tranche:
Cela dit, pour une simple opération de ce genre, vous devez tout simplement utiliser:
Vous ne pouvez pas modifier la liste que vous itération, sinon vous obtenez cette étrange type de résultat. Pour ce faire, vous devez effectuer une itération sur une copie de la liste:
Il supprime la première occurrence, puis vérifie le numéro suivant dans la séquence. Depuis la séquence a changé, il prend le nombre impair suivant et ainsi de suite...
-...
ce que vous voulez faire est:
ou
Ce sera de préserver objet d'origine
letters
a été pointant vers. D'autres options comme,letters = []
serait de créer un nouvel objet et le pointletters
: ancien objet serait généralement être récupérées après un certain temps.La raison de ne pas toutes les valeurs ont été supprimés, c'est que vous êtes à la modification de la liste lors de l'itération sur elle.
ETA: si vous souhaitez filtrer des valeurs d'une liste vous pouvez utiliser interprétations de la liste comme ceci:
Probablement python utilise des pointeurs et la suppression commence à l'avant. La variable "lettres" à la deuxième ligne partiellement a une valeur différente de celle tha variable "lettres" à la troisième ligne. Lorsque je est 1 alors a est supprimé, lorsque je est 2 alors b a été déplacé à la position 1 et c est supprimé. Vous pouvez essayer d'utiliser le "tout".
Je pense que c'est ce qui explique le problème un peu mieux, le bloc de code fonctionne, alors que celui du bas ne marche pas.
Les éléments qui sont "gardés" en bas de la liste de ne jamais obtenir de l'imprimé, parce que vous êtes modifiying la liste, vous êtes à parcourir, ce qui est une recette pour un désastre.
OK, je suis un peu en retard à la fête ici, mais j'ai pensé à ce sujet et après avoir regardé Python (Disponible) mise en œuvre du code, avoir une explication que j'aime. Si quelqu'un sait pourquoi il est idiot ou de mauvaise, je vous en serais reconnaissant audience les raisons pour lesquelles.
La question se déplace à travers une liste à l'aide d'un itérateur, tout en permettant que la liste à modifier.
Tous les itérateur est tenu de faire est de vous dire quel élément dans l' (dans ce cas) la liste vient après l'élément courant (c'est à dire avec la fonction next ()).
Je crois que la façon dont les itérateurs sont actuellement mis en œuvre, ils n'en garder la trace de l'indice du dernier élément qu'ils itéré. En regardant dans iterobject.c on peut voir ce qui semble être une définition d'un itérateur:
où
it_seq
points de la séquence est itéré etit_index
donne l'indice du dernier élément fourni par l'itérateur.Lorsque l'itérateur vient de fournir le nème de l'élément et on supprime cet élément de la séquence, la correspondance entre la liste des éléments et de leurs indices de changements. L'ancien (n+1)st de l'élément devient le nème d'aussi loin que l'itérateur. En d'autres termes, l'itérateur pense maintenant que ce qui était de la "prochaine" de l'élément dans la séquence est en fait l'élément.
Donc, on demande de donner le point suivant, il va donner à l'ancien (n+2)ème de l'élément(c'est à dire la nouvelle (n+1)st de l'élément).
En conséquence, pour que le code en question, l'itérateur est
next()
méthode va donner uniquement les n+0, n+2, n+4, ... les éléments de la liste initiale. Le n+1, n+3, n+5, ... articles ne seront jamais exposés à laremove
déclaration.Bien que l'activité prévue des le code en question est claire (au moins pour une personne), il serait probablement besoin de beaucoup plus d'introspection pour un itérateur pour surveiller les changements dans la séquence, il parcourt et, ensuite, à agir dans un "homme" de la mode.
Si les itérateurs pourrait retourner avant le ou les éléments d'une séquence, il y a peut être un travail en général, mais comme il est, vous avez besoin pour effectuer une itération sur une copie de la liste, et être certain pas pour supprimer tous les éléments avant de l'itérateur arrive jusqu'à eux.