python:列表索引超出范围错误

python : list index out of range error

我写了一个简单的python程序

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

这给了我错误的"列表索引超出范围"在行if l[i]==0:上。

在调试之后,我可以发现i正在增加,列表也在减少。但是,我有循环终止条件i < len(l)。那我为什么会犯这样的错误呢?


在迭代过程中,您减少了列表的长度l,因此当您接近range语句中索引的末尾时,其中一些索引不再有效。

看起来你想做的是:

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

它将返回一个没有任何元素为零的l的副本(顺便说一下,该操作称为列表理解)。您甚至可以将最后一部分缩短为if x,因为非零数字的值为True

在编写代码的过程中,不存在i < len(l)的循环终止条件,因为len(l)是在循环之前预先计算的,而不是在每次迭代时重新计算的。不过,你可以这样写:

1
2
3
4
5
6
i = 0
while i < len(l):
   if l[i] == 0:
       l.pop(i)
   else:
       i += 1


表达式len(l)只计算一次,此时,range()内置的计算。当时构造的测距对象没有变化,它不可能知道对象l的任何信息。

p.s.l是一个糟糕的值名称!它看起来像数字1或大写字母I。


您在迭代列表时更改了列表的大小,这可能不是您想要的,也是导致错误的原因。

编辑:正如其他人回答和评论的那样,列表理解作为第一选择更好,尤其是在回答这个问题时。出于这个原因,我提供了一个替代方案,虽然不是最好的答案,但它仍然解决了这个问题。

因此,在这个注释中,您还可以使用filter,它允许您调用一个函数来评估您不想要的列表中的项目。

例子:

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

活到老学到老。简单更好,除非你需要复杂的事情。


MarkRushakoff所说的是正确的,但是如果您以相反的方向迭代,那么也可以从for循环的列表中删除元素。例如。,

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

它就像一座从上到下倒塌的高楼:即使它在倒塌的中间,你仍然可以"进入"它,参观尚未倒塌的楼层。


我认为解决这个问题的最佳方法是:

1
2
3
l = [1, 2, 3, 0, 0, 1]
while 0 in l:
    l.remove(0)

我不再重复列表,而是删除0,直到列表中没有任何0


列表理解将引导您找到解决方案。

但是在python中复制对象的正确方法是使用python模块复制-浅层和深层复制操作。

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

如果不是这个,

1
2
3
4
5
6
7
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

那么,您自己的代码就可以工作了。但是对于优化,列表理解是一个很好的解决方案。


问题是,您试图修改在使用列表len()的循环中引用的列表。当您从列表中删除该项时,新的len()将在下一个循环中计算。

例如,在第一次运行之后,当您使用l.pop(i)删除(i)时,成功地发生了这种情况,但在下一个循环中,列表的长度发生了更改,因此所有索引号都已移位。在某一点上,循环试图遍历引发错误的简短列表。

在循环外部执行此操作是可行的,但是最好在循环之前先声明并清空列表,然后在循环内部将要保留的所有内容追加到新列表。

对于那些可能遇到同样问题的人。


我使用的是python 3.3.5。上面使用while循环的解决方案对我不起作用。即使我把print (i)放在len(l)之后,它还是给了我一个错误。我在命令行(shell)中运行了相同的代码[运行函数时弹出的窗口]它运行时没有出错。我所做的是在主程序的函数外部计算len(l),并将长度作为参数传递。它起作用了。Python有时很奇怪。


我认为大多数解决方案都会在这里讨论列表理解,但是如果您希望执行就地删除,并将空间复杂性保持在o(1);解决方案是:

1
2
3
4
5
6
i = 0
for j in range(len(arr)):
if (arr[j] != 0):
    arr[i] = arr[j]
    i +=1
arr = arr[:i]