Python: liste de l'index hors de portée erreur

j'ai écrit un programme python simple

l=[1,2,3,0,0,1]
for i in range(0,len(l)):
       if l[i]==0:
           l.pop(i)

Cela me donne l'erreur "list index out of range", sur la ligne if l[i]==0:

Après le débogage j'ai pu comprendre que i devient incrémenté et la liste se réduit.

Cependant, j'ai la condition de terminaison de boucle i < len(l). Alors pourquoi je reçois une telle erreur?

22
demandé sur abyx 2009-11-25 20:57:54

7 réponses

vous réduisez la longueur de votre liste l comme vous itérez sur elle, de sorte que vous approchez la fin de vos indices dans la déclaration de portée, certains de ces indices ne sont plus valides.

regarde vous aimez ce que vous voulez faire, c'est:

l = [x for x in l if x != 0]

qui retourne une copie de l sans aucun des éléments qui étaient à zéro (cette opération est appelée compréhension de liste, soit dit en passant). Vous pourriez même raccourcir la dernière partie à juste if x, puisque les nombres non-zéro évaluent à True.

il n'existe pas de condition de terminaison de boucle de i < len(l), dans la façon dont vous avez écrit le code, parce que len(l)pré calculé avant la boucle, non réévalué à chaque itération. Vous écrire de telle manière, cependant:

i = 0
while i < len(l):
   if l[i] == 0:
       l.pop(i)
   else:
       i += 1
42
répondu Mark Rushakoff 2009-11-25 18:14:28

len(l) n'est évalué qu'une seule fois, à l'instant le range() l'builtin est évalué. L'objet range construit à cette époque ne change pas; il ne peut rien savoir de l'objet l.

P.S. l est un mauvais nom pour une valeur! Il ressemble au chiffre 1, ou la capitale de la lettre I.

14
répondu Jonathan Feinberg 2009-11-25 18:01:32

vous changez la taille de la liste tout en itérant dessus, ce qui n'est probablement pas ce que vous voulez et est la cause de votre erreur.

Edit: comme d'autres ont répondu et commenté, les interprétations de listes sont un meilleur premier choix et surtout en réponse à cette question. J'ai proposé cette solution comme alternative pour cette raison, et bien que ce ne soit pas la meilleure réponse, elle résout toujours le problème.

filter, qui vous permet d'appeler une fonction à évaluer les éléments dans la liste, vous ne voulez pas.

Exemple:

>>> l = [1,2,3,0,0,1]
>>> filter(lambda x: x > 0, l)
[1, 2, 3]

Vivre et apprendre. Simple est mieux, sauf quand vous avez besoin que les choses soient complexes.

5
répondu jathanism 2009-11-26 21:05:34

Marque Rushakoff dit est vrai, mais si vous itérer dans la direction opposée, il est possible de supprimer des éléments de la liste dans la boucle for. E. g.,

x = [1,2,3,0,0,1]
for i in range(len(x)-1, -1, -1):
    if x[i] == 0:
        x.pop(i)

c'est comme un grand bâtiment qui tombe de haut en bas: même s'il est au milieu de l'effondrement, vous pouvez quand même y "entrer" et visiter encore-à-être-planchers effondrés.

4
répondu 8day 2017-05-23 12:17:57

le problème est que vous avez essayé de modifier la liste que vous référenciez dans la boucle qui utilise la liste len(). Lorsque vous supprimez l'élément de la liste, alors le nouveau len() est calculée sur la boucle suivante.

par exemple, après la première exécution, lorsque vous supprimez (i) en utilisant l.pop(i), cela s'est produit avec succès mais sur la boucle suivante La longueur de la liste a changé donc tous les indices ont été déplacés. À un certain point la boucle tente de courir sur un court-circuit liste lancer l'erreur.

faire cela en dehors de la boucle fonctionne, cependant il serait préférable de construire et de nouvelle liste en déclarant d'abord et la liste vide avant la boucle, et plus tard dans la boucle ajouter tout ce que vous voulez garder à la nouvelle liste.

Pour ceux d'entre vous qui ont le même problème.

1
répondu StevenSavant 2015-06-16 08:01:05

compréhension de Liste vous mènera à une solution.

mais la bonne façon de copier un objet en python est d'utiliser module python copie opérations de copie superficielles et profondes.

l=[1,2,3,0,0,1]
for i in range(0,len(l)):
   if l[i]==0:
       l.pop(i)

Si au lieu de cela,

import copy
l=[1,2,3,0,0,1]
duplicate_l = copy.copy(l)
for i in range(0,len(l)):
   if l[i]==0:
       m.remove(i)
l = m

alors, votre propre code aurait fonctionné. Mais pour l'optimisation, la compréhension de liste est une bonne solution.

1
répondu Manish Tripathi 2016-05-30 12:06:17

j'utilise python 3.3.5. La solution ci-dessus d'utiliser while loop ne fonctionnait pas pour moi. Même si je mets print (i) après len(l) il m'a donné une erreur. J'ai lancé le même code dans la ligne de commande (shell)[ fenêtre qui apparaît lorsque nous exécutons une fonction] il s'exécute sans erreur. Ce que j'ai fait a été calculé Len(l) en dehors de la fonction dans le programme principal et passé la longueur comme un paramètre. Il a travaillé. Python est bizarre parfois.

1
répondu Aseem 2016-09-09 10:28:02