for循环索引可以依赖于列表的变化长度吗?

时间:2014-08-06 23:39:51

标签: python

我写了一些代码,其中forloop索引在一个范围内变化,具体取决于列表的长度,并且列表的长度在循环内是可变的。这是一个简化的代码:

>>> ml = [1,2,3]
>>> for i in range(0, len(ml)):
...     if ml[i] == 2:
...         ml.pop(i)
...     i
... 
0
2
1
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
IndexError: list index out of range

我猜{for len(ml)在forloop的第一次迭代中被评估一次,而不是在后面的迭代中,因此索引超出范围。

但是可以在迭代中更新索引范围吗?感谢。

3 个答案:

答案 0 :(得分:4)

new_list = [x for x in my_list if x != 2]

好多了或

new_list = filter(lambda x:x!=2,my_list)

你不应该在迭代列表时真正删除元素,除非你有一个非常非常好的(我从来没有听说过这么好)原因

如果您希望元素替换当前列表

my_list[:] = [x for x in my_list if x != 2]

或者你可以简单地覆盖它,让pythons非常好的垃圾收集器删除旧的

my_list = [x for x in my_list if x != 2]

答案 1 :(得分:3)

range(0, len(ml))评估一次,并生成i的值列表。

您可以通过while循环简单地替换for循环:

i = 0
while i < len(ml):
  if ml[i] == 2:
    ml.pop(i)
    continue
  i+=1

答案 2 :(得分:1)

这种行为是有道理的,因为你实际上没有遍历列表,而是在范围内:

ml = [1, 2, 3]

for i in range(0, len(ml)):
    print(i)

提供以下输出:

0
1
2

使用for item in ml:实际上遍历列表:

ml = [1, 2, 3]
    for i in ml:
        if i == 2:
            ml.pop(i)
        print(i)

结果:

1
2

回应此处的评论,可以更好地了解发生了什么:

ml = [1, 2, 3, 4, 5, 6, 7]
for i in ml:
   if i == 2:
       ml.pop(1) # pop second element in list
   print(i)

给出以下输出:

1
2
4
5
6
7

使用while循环可以得到相同的结果:

ml = [1, 2, 3, 4, 5, 6, 7]

i = 0
while i < len(ml):
    print(ml[i])
    if ml[i] == 2:
        ml.pop(i)
    i+=1

1
2
4
5
6
7

这意味着您可以弹出元素,但是您无法确保所有元素都已正确处理。