惯用语方式否定一个过滤器。

6

如何用最自然的方式编写一个带有否定条件的filter(过滤器)?

例如:

is_even= lambda x : x % 2 == 0
odd_numbers= filter( lambda x: not is_even(x), range(10) )

当然,你可以直接使用列表推导式 - 但这时你就不需要使用filter了。
如果有人想知道,我是在尝试根据条件拆分列表时遇到这个问题的。

如果有人想知道,我正在尝试根据条件拆分列表 - loopbackbee
那个缺少的 ) 是打字错误吗? - Bhargav Rao
你能告诉我们你实际上想要做什么吗?请提供更广泛的描述。你发布的内容有什么问题吗? - Reut Sharabani
@ReutSharabani 我在评论中提到了这一点,但我会将其移动到问题本身。我写的没有什么“错误”的地方,只是想知道是否有更习惯用语或更简洁的方法来做到这一点。 - loopbackbee
太好了。我试图在答案中清楚地解释Python 2和3之间的区别。实际上,你在问题中提供的示例在2和3中给出了不同的结果。 - Lack
显示剩余5条评论
2个回答

10

itertools模块包括 ifilter()ifilterfalse(),它们分别筛选函数返回为TrueFalse的元素。

odd_numbers = ifilterfalse(is_even, range(10))

注意,在Python 2中,filterifilter之间存在差异:在这里,odd_numbers将是一个迭代器,而filter()会返回一个列表(请参阅itertools.ifilter Vs. filter Vs. list comprehensions)。如果您确实想要构建一个列表,那么您使用not的示例似乎很好,假设您决定使用filter - 列表推导可能更加“习惯用法”(List filtering: list comprehension vs. lambda + filter)。

在Python 3中,filter()构造一个迭代器,而不是列表,itertools.filterfalse()是补集。


2
有人对为什么作者选择了ifilterfalse而不是ireject有什么见解吗? - wpcarro

3

基于谓词进行拆分被称为partition。我认为实现partition作为一个单独的函数比为奇数和偶数重复其内部实现更符合惯用语法。Python 3的Itertools Recipes提供了以下实现:

def partition(pred, iterable):
    'Use a predicate to partition entries into false entries and true entries'
    # partition(is_odd, range(10)) --> 0 2 4 6 8   and  1 3 5 7 9
    t1, t2 = tee(iterable)
    return filterfalse(pred, t1), filter(pred, t2)

它使用了该模块中描述的filterfalsetee。因此,您的最高级代码应如下所示:
odds, evens = partition(is_even, range(10))

是的,如果您正在使用列表的两个部分,那么这是解决实际问题的更好方案。 - Lack
这可能值得在我链接的问题中发布,因为还没有人提到它。我的问题特别是出于好奇而不是实际需要解决实际分区(已经有很多答案了)。 - loopbackbee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接