在python 3中过滤已过滤的列表

时间:2015-05-10 16:16:38

标签: python-3.x

我对Python 3.x中过滤器函数的行为感到困惑 假设下一个代码:

>>> test = [1, 2, 3, 4, 5, 6, 7, 8]
>>> for num in range(4):
       test = filter( lambda x: x != num, test)
>>> print(list(test))
    # [1, 2, 4, 5, 6, 7, 8]

我认为测试变量将包含连续过滤范围(4)中存在的值(num)的结果,但最终列表根本没有被过滤!。

有人可以向我解释这种行为吗?如果可能的话,如何获得预期的结果     #[4,5,6,7,8]

注意:我的原始代码并不像这个简单,但这只是为了说明我发现错误的地方。

3 个答案:

答案 0 :(得分:2)

问题是filter返回一个迭代器,迭代器没有“冻结”num的值,如下面的代码所示:

>>> test = [1, 2, 3, 4, 5, 6, 7, 8]
>>> for num in range(4):
...     test = filter(lambda x: print(x, '!=', num) or x != num, test)
... 
>>> list(test)
1 != 3
1 != 3
1 != 3
1 != 3
2 != 3
2 != 3
2 != 3
2 != 3
3 != 3
4 != 3
[...]
[1, 2, 4, 5, 6, 7, 8]

如您所见,当list(test)和迭代器被评估时,仅使用num的最后一个值。

一个解决方案可能是在每次迭代中使用list(filter(...)),因为它已经被提出。

但是如果你想节省内存,这就是你如何“冻结”num:

>>> import functools
>>> test = [1, 2, 3, 4, 5, 6, 7, 8]
>>> not_equal = lambda x, y: x != y
>>> for num in range(4):
...     test = filter(functools.partial(not_equal, num), test)
... 
>>> list(test)
[4, 5, 6, 7, 8]

(当然,这只是一个例子。尽量让你的代码更具可读性。)

通常,您需要做的是保持对num的值的引用,并避免在内部范围中按名称引用它。

答案 1 :(得分:0)

问题是filter返回过滤器对象的实例。对于您编写的代码,您必须使用过滤器对象在循环中创建新列表

for num in range(4):
    test = list( filter( lambda x: x != num, test) )

答案 2 :(得分:0)

filter对象仍然包含test中的每个对象。因此,请尝试以下方法:

test = [1, 2, 3, 4, 5, 6, 7, 8]
for num in range(4):
   test = filter( lambda x: x != num, list(test))
print(list(test))

通过将list投放到3 rd 行中的test,我们可以有效地删除我们不想要的项目:

>>> print(list(test))
[4, 5, 6, 7, 8]
>>>