I have written a simple python program
我已经编写了一个简单的python程序。
l=[1,2,3,0,0,1]
for i in range(0,len(l)):
if l[i]==0:
l.pop(i)
This gives me error 'list index out of range' on line if l[i]==0:
如果l[i]==0,这将使我的错误“列表索引超出范围”。
After debugging I could figure out that i
is getting incremented and list is getting reduced.
However, I have loop termination condition i < len(l)
. Then why I am getting such error?
调试之后,我可以发现,我的增量和列表都在减少。然而,我有循环终止条件I < len(l)。那么我为什么会犯这样的错误呢?
7 个解决方案
#1
39
You are reducing the length of your list l
as you iterate over it, so as you approach the end of your indices in the range statement, some of those indices are no longer valid.
当您迭代它时,您正在减少列表l的长度,因此当您在范围语句中接近您的索引的末尾时,其中一些索引不再有效。
It looks like what you want to do is:
看起来你想做的是:
l = [x for x in l if x != 0]
which will return a copy of l
without any of the elements that were zero (that operation is called a list comprehension, by the way). You could even shorten that last part to just if x
, since non-zero numbers evaluate to True
.
这将返回l的副本,而不包含任何为零的元素(顺便说一下,该操作称为列表理解)。你甚至可以把最后的部分缩短为x,因为非零的数值是正确的。
There is no such thing as a loop termination condition of i < len(l)
, in the way you've written the code, because len(l)
is precalculated before the loop, not re-evaluated on each iteration. You could write it in such a way, however:
我< len(l)的循环终止条件是不存在的,就像您编写代码的方式一样,因为len(l)是在循环之前预先计算的,而不是在每次迭代中重新计算。你可以这样写:
i = 0
while i < len(l):
if l[i] == 0:
l.pop(i)
else:
i += 1
#2
14
The expression len(l)
is evaluated only one time, at the moment the range()
builtin is evaluated. The range object constructed at that time does not change; it can't possibly know anything about the object l
.
表达式len(l)只计算一次,此时距离()builtin被求值。在那个时候构造的范围对象不会改变;它不可能知道物体l。
P.S. l
is a lousy name for a value! It looks like the numeral 1, or the capital letter I.
P.S. l是一个很糟糕的值!它看起来像数字1,或者大写的I。
#3
5
You're changing the size of the list while iterating over it, which is probably not what you want and is the cause of your error.
您正在更改列表的大小,同时遍历它,这可能不是您想要的,而是您错误的原因。
Edit: As others have answered and commented, list comprehensions are better as a first choice and especially so in response to this question. I offered this as an alternative for that reason, and while not the best answer, it still solves the problem.
编辑:就像其他人回答和评论的那样,列表的理解是最好的选择,尤其是在回答这个问题的时候。我提出这是一个替代的理由,虽然不是最好的答案,但它仍然解决了问题。
So on that note, you could also use filter
, which allows you to call a function to evaluate the items in the list you don't want.
因此,在这一点上,您还可以使用filter,它允许您调用一个函数来评估您不想要的列表中的项。
Example:
例子:
>>> l = [1,2,3,0,0,1]
>>> filter(lambda x: x > 0, l)
[1, 2, 3]
Live and learn. Simple is better, except when you need things to be complex.
活到老,学到老。简单是更好的,除非你需要复杂的东西。
#4
3
What Mark Rushakoff said is true, but if you iterate in the opposite direction, it is possible to remove elements from the list in the for-loop as well. E.g.,
Mark Rushakoff说的是正确的,但是如果您在相反的方向迭代,也可以从for循环中删除元素。例如,
x = [1,2,3,0,0,1]
for i in range(len(x)-1, -1, -1):
if x[i] == 0:
x.pop(i)
It's like a tall building that falls from top to bottom: even if it is in the middle of collapse, you still can "enter" into it and visit yet-to-be-collapsed floors.
就像一幢高楼从上到下都是一样的:即使是在倒塌的中间,你仍然可以“进入”它,去参观尚未倒塌的地板。
#5
0
The problem was that you attempted to modify the list you were referencing within the loop that used the list len()
. When you remove the item from the list, then the new len()
is calculated on the next loop.
问题是,您试图修改在使用list len()的循环中引用的列表。当您从列表中删除项目时,新的len()将在下一个循环中计算。
For example, after the first run, when you removed (i)
using l.pop(i)
, that happened successfully but on the next loop the length of the list has changed so all index numbers have been shifted. To a certain point the loop attempts to run over a shorted list throwing the error.
例如,在第一次运行之后,当您删除(i)使用l.pop(i)时,这是成功的,但是在下一个循环中,列表的长度发生了变化,因此所有的索引号都发生了移位。在某一点上,该循环试图运行一个抛出错误的空列表。
Doing this outside the loop works, however it would be better to build and new list by first declaring and empty list before the loop, and later within the loop append everything you want to keep to the new list.
在循环之外执行这个操作,但是最好在循环之前先声明和清空列表,然后在循环中添加您想要保存到新列表的所有内容。
For those of you who may have come to the same problem.
对于你们中可能遇到同样问题的人。
#6
0
List comprehension will lead you to a solution.
清单的理解会让你找到解决方法。
But the right way to copy a object in python is using python module copy - Shallow and deep copy operations.
但是在python中复制对象的正确方法是使用python模块复制——浅层和深度复制操作。
l=[1,2,3,0,0,1]
for i in range(0,len(l)):
if l[i]==0:
l.pop(i)
If instead of this,
如果不是这样,
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
Then, your own code would have worked. But for optimization, list comprehension is a good solution.
然后,您自己的代码就可以工作了。但是对于优化,列表理解是一个很好的解决方案。
#7
0
I am using python 3.3.5. The above solution of using while loop did not work for me. Even if i put print (i)
after len(l)
it gave me an error. I ran the same code in command line (shell)[ window that pops up when we run a function] it runs without error. What i did was calculated len(l) outside the function in main program and passed the length as a parameter. It worked. Python is weird sometimes.
我使用的是python 3.3.5。使用while循环的上述解决方案对我不起作用。即使我在len(l)后面加上print (i),它也给了我一个错误。我在命令行(shell)中运行了相同的代码(当我们运行一个函数时弹出窗口),它运行时没有错误。我所做的是在主程序的函数外计算len(l),并将长度作为参数传递。它工作。Python是奇怪的有时。
#1
39
You are reducing the length of your list l
as you iterate over it, so as you approach the end of your indices in the range statement, some of those indices are no longer valid.
当您迭代它时,您正在减少列表l的长度,因此当您在范围语句中接近您的索引的末尾时,其中一些索引不再有效。
It looks like what you want to do is:
看起来你想做的是:
l = [x for x in l if x != 0]
which will return a copy of l
without any of the elements that were zero (that operation is called a list comprehension, by the way). You could even shorten that last part to just if x
, since non-zero numbers evaluate to True
.
这将返回l的副本,而不包含任何为零的元素(顺便说一下,该操作称为列表理解)。你甚至可以把最后的部分缩短为x,因为非零的数值是正确的。
There is no such thing as a loop termination condition of i < len(l)
, in the way you've written the code, because len(l)
is precalculated before the loop, not re-evaluated on each iteration. You could write it in such a way, however:
我< len(l)的循环终止条件是不存在的,就像您编写代码的方式一样,因为len(l)是在循环之前预先计算的,而不是在每次迭代中重新计算。你可以这样写:
i = 0
while i < len(l):
if l[i] == 0:
l.pop(i)
else:
i += 1
#2
14
The expression len(l)
is evaluated only one time, at the moment the range()
builtin is evaluated. The range object constructed at that time does not change; it can't possibly know anything about the object l
.
表达式len(l)只计算一次,此时距离()builtin被求值。在那个时候构造的范围对象不会改变;它不可能知道物体l。
P.S. l
is a lousy name for a value! It looks like the numeral 1, or the capital letter I.
P.S. l是一个很糟糕的值!它看起来像数字1,或者大写的I。
#3
5
You're changing the size of the list while iterating over it, which is probably not what you want and is the cause of your error.
您正在更改列表的大小,同时遍历它,这可能不是您想要的,而是您错误的原因。
Edit: As others have answered and commented, list comprehensions are better as a first choice and especially so in response to this question. I offered this as an alternative for that reason, and while not the best answer, it still solves the problem.
编辑:就像其他人回答和评论的那样,列表的理解是最好的选择,尤其是在回答这个问题的时候。我提出这是一个替代的理由,虽然不是最好的答案,但它仍然解决了问题。
So on that note, you could also use filter
, which allows you to call a function to evaluate the items in the list you don't want.
因此,在这一点上,您还可以使用filter,它允许您调用一个函数来评估您不想要的列表中的项。
Example:
例子:
>>> l = [1,2,3,0,0,1]
>>> filter(lambda x: x > 0, l)
[1, 2, 3]
Live and learn. Simple is better, except when you need things to be complex.
活到老,学到老。简单是更好的,除非你需要复杂的东西。
#4
3
What Mark Rushakoff said is true, but if you iterate in the opposite direction, it is possible to remove elements from the list in the for-loop as well. E.g.,
Mark Rushakoff说的是正确的,但是如果您在相反的方向迭代,也可以从for循环中删除元素。例如,
x = [1,2,3,0,0,1]
for i in range(len(x)-1, -1, -1):
if x[i] == 0:
x.pop(i)
It's like a tall building that falls from top to bottom: even if it is in the middle of collapse, you still can "enter" into it and visit yet-to-be-collapsed floors.
就像一幢高楼从上到下都是一样的:即使是在倒塌的中间,你仍然可以“进入”它,去参观尚未倒塌的地板。
#5
0
The problem was that you attempted to modify the list you were referencing within the loop that used the list len()
. When you remove the item from the list, then the new len()
is calculated on the next loop.
问题是,您试图修改在使用list len()的循环中引用的列表。当您从列表中删除项目时,新的len()将在下一个循环中计算。
For example, after the first run, when you removed (i)
using l.pop(i)
, that happened successfully but on the next loop the length of the list has changed so all index numbers have been shifted. To a certain point the loop attempts to run over a shorted list throwing the error.
例如,在第一次运行之后,当您删除(i)使用l.pop(i)时,这是成功的,但是在下一个循环中,列表的长度发生了变化,因此所有的索引号都发生了移位。在某一点上,该循环试图运行一个抛出错误的空列表。
Doing this outside the loop works, however it would be better to build and new list by first declaring and empty list before the loop, and later within the loop append everything you want to keep to the new list.
在循环之外执行这个操作,但是最好在循环之前先声明和清空列表,然后在循环中添加您想要保存到新列表的所有内容。
For those of you who may have come to the same problem.
对于你们中可能遇到同样问题的人。
#6
0
List comprehension will lead you to a solution.
清单的理解会让你找到解决方法。
But the right way to copy a object in python is using python module copy - Shallow and deep copy operations.
但是在python中复制对象的正确方法是使用python模块复制——浅层和深度复制操作。
l=[1,2,3,0,0,1]
for i in range(0,len(l)):
if l[i]==0:
l.pop(i)
If instead of this,
如果不是这样,
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
Then, your own code would have worked. But for optimization, list comprehension is a good solution.
然后,您自己的代码就可以工作了。但是对于优化,列表理解是一个很好的解决方案。
#7
0
I am using python 3.3.5. The above solution of using while loop did not work for me. Even if i put print (i)
after len(l)
it gave me an error. I ran the same code in command line (shell)[ window that pops up when we run a function] it runs without error. What i did was calculated len(l) outside the function in main program and passed the length as a parameter. It worked. Python is weird sometimes.
我使用的是python 3.3.5。使用while循环的上述解决方案对我不起作用。即使我在len(l)后面加上print (i),它也给了我一个错误。我在命令行(shell)中运行了相同的代码(当我们运行一个函数时弹出窗口),它运行时没有错误。我所做的是在主程序的函数外计算len(l),并将长度作为参数传递。它工作。Python是奇怪的有时。