我正在尝试过滤一些我正在使用的数据,以便在我的测量设备中删除一些伪像,例如负数和错误。我一直在玩使用发电机这样做的想法。我使用的是Python 2.7.2
testlist = [12,2,1,1,1,0,-3,-3,-1]
gen = (i for i, x in enumerate(testlist) if x < 0 or x > 2.5)
for i in gen: testlist.pop(i)
print testlist
返回:
[2, 1, 1, 1, 0, -3]
我的问题是为什么-3值出现在更新的“测试列表”中?
答案 0 :(得分:7)
当您从列表中删除项目时,项目更改后的索引(它们都向下移动一个)。结果,生成器将跳过一些项目。尝试添加一些打印语句,以便您可以看到正在发生的事情:
for i in gen:
print i
print testlist
testlist.pop(i)
输出:
0
[12, 2, 1, 1, 1, 0, -3, -3, -1]
5
[2, 1, 1, 1, 0, -3, -3, -1]
6
[2, 1, 1, 1, 0, -3, -1]
您需要删除索引0,5,5,5处的项目。生成器生成索引0,5,6。这是有道理的,因为enumerate
返回0, 1, 2, ...
等。它赢了不会连续两次返回相同的索引。
一次删除一个元素也非常低效。这需要多次移动数据,最坏情况下的性能为O(n 2 )。您可以使用列表推导。
testlist = [x for x in testlist if 0 <= x <= 2.5]
答案 1 :(得分:1)
您正在修改您正在处理的列表,有点类似于修改索引值,例如,来自 in 循环的for循环,在某些其他语言中。将此方法视为替代方案:
testlist = [x for x in testlist if x >= 0 and x <= 2.5]
使用list comprehension应该更直接地工作,虽然它不是generator expression,但可以简单地改为1:
testlist = (x for x in testlist if x >= 0 and x <= 2.5)
答案 2 :(得分:1)
让我们考虑一个更简单的输入:
[-3, -4, -5]
首先(0,-3)取自枚举器。 0被添加到生成器。 for循环注意到生成器中有一个新元素,并删除-3:
[-4, -5]
从枚举器中获取一个新元素。枚举器会记住第一个元素,所以现在它将采用第二个元素:-5。 -5以相同的方式从列表中删除。 -4仍然存在。
顺便说一句,一个更简单的方法来做你正在尝试的事情如下:
testlist = filter(lambda x: x >= 0 and x <= 2.5, testlist)
答案 3 :(得分:1)
更好的方法是使用列表推导来创建新的过滤列表:
testlist = [12,2,1,1,1,0,-3,-3,-1]
testlist[:] = [x for x in testlist if 0 <= x <= 2.5]
,并提供:
[2, 1, 1, 1, 0]