聪明any()之类的函数检查至少n个元素是否为True?

Loi*_*icM 5 python built-in python-3.x

假设我有一个iterable(在我的例子中是一个列表):

l = [True, False, False, True]
Run Code Online (Sandbox Code Playgroud)

我知道检查这些元素中至少有一个是否为True的最简单,最快捷的方法就是使用any(l),这将返回True.

但是,如果我想检查至少有两个元素True呢?我的目标是以尽可能最快的方式处理它.

我的代码现在看起来像这样(对于两个元素):

def check_filter(l):
    if len([i for i in filter(None, l)]) > 1:
        return True
return False
Run Code Online (Sandbox Code Playgroud)

这比any()我慢了大约10倍,而且对我来说似乎不是非常pythonic.

MSe*_*ert 12

您可以简单地在序列上使用迭代器,并检查any迭代器上的返回值始终为True for n-times:

def check(it, num):
    it = iter(it)
    return all(any(it) for _ in range(num))

>>> check([1, 1, 0], 2)
True

>>> check([1, 1, 0], 3)
False
Run Code Online (Sandbox Code Playgroud)

这里的关键点是迭代器会记住它最后的位置,因此每个any调用都将从最后一个调用开始.和包装它all确保它早只要一离开any就是False.

至少在性能方面,这应该比大多数其他方法更快.但是以可读性为代价.


如果你想比基于的解决方案更快,map并且itertools.repeat可以稍快一点:

from itertools import repeat

def check_map(it, num):
    return all(map(any, repeat(iter(it), num)))
Run Code Online (Sandbox Code Playgroud)

针对其他答案进行基准测试:

# Second "True" element is in the last place
lst = [1] + [0]*1000 + [1]

%timeit check_map(lst, 2)  # 10000 loops, best of 3: 20.3 µs per loop
%timeit check(lst, 2)      # 10000 loops, best of 3: 23.5 µs per loop
%timeit many(lst, 2)       # 10000 loops, best of 3: 153 µs per loop
%timeit sum(l) >= 2        # 100000 loops, best of 3: 19.6 µs per loop

# Second "True" element is the second item in the iterable
lst = [1, 1] + [0]*1000

%timeit check_map(lst, 2)  # 100000 loops, best of 3: 3.05 µs per loop
%timeit check(lst, 2)      # 100000 loops, best of 3: 6.39 µs per loop
%timeit many(lst, 2)       # 100000 loops, best of 3: 5.02 µs per loop
%timeit sum(lst) >= 2      # 10000 loops, best of 3: 19.5 µs per loop
Run Code Online (Sandbox Code Playgroud)