为什么我不能在通常的for语句中编写这段代码?

时间:2013-09-26 05:57:05

标签: python for-loop iterator

我刚刚在这里阅读了一篇关于如何从两个列表中过滤值的帖子。python: How to remove values from 2 lists based on what's in 1 list

我尝试使用forzip自己编写一些代码,但结果是错误的,有人能帮我理解吗?

xVar = [1, 2, 3, 4, 5, 6, 7]
yVar = [11, 22, 33, 44, 55, 66, 77]

z = zip(xVar, yVar)
zFiltered = [(x, y) for x, y in z if y < 50]
print zFiltered # Correct, prints [(1, 11), (2, 22), (3, 33), (4, 44)]

for (x, y) in z:
    if y > 50:
        z.remove((x, y))

print z # Wrong, prints [(1, 11), (2, 22), (3, 33), (4, 44), (6, 66)]

为什么会这样?我尝试使用pdb,发现在z.remove((5, 55))后,(x, y)的值为(7, 77)(6, 66)被嘲笑,我认为for是通过索引分配(x, y),删除(5, 55)会违反原始索引,如果是这样,我如何使用for语句执行相同的操作?还有其他任何陷阱吗?

2 个答案:

答案 0 :(得分:3)

尝试这个列表理解,它将根据条件选择压缩列表中的元素(基本上与从列表中删除不满足此条件的元素相反,但它会产生相同的结果)。

z = [(x, y) for (x, y) in z if y <= 50]

如果要在迭代时删除列表中的元素,则必须向后迭代,因为每次删除列表中的项目时,列表中具有较高索引的所有元素都会向下移动到较低的索引。

你可以像这样进行这样的迭代:

for i in xrange(len(z) -1, -1, -1):
    if z[i][1] > 50:
        z.remove(z[i])

答案 1 :(得分:2)

问题是当你在迭代它时从列表中删除一个项目时,它的内部结构就会失败,并且会跳过项目。解决此问题的简单方法是通过添加[:]来制作列表的副本。

for (x, y) in z[:]:
    ...

现在您可以对原始列表进行更改,因为它没有被迭代。