LoicM LoicM -4 years ago 77
Python Question

clever any() like function to check if at least n elements are True?

Say I have an iterable (in my case a list):

l = [True, False, False, True]


I know that the easiest and fastest way to check if at least one of those elements is True is simply to use
any(l)
, which will return
True
.

But what if I want to check that at least two elements are
True
?
My goal is to process it in the fastest way possible.

My code right now looks like this (for two elements):

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


This is about 10 times slower than
any()
, and does not seem very pythonic to me.

Answer Source

You could simply use an iterator over the sequence and check that any on the iterator returns always 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

The key point here is that an iterator remembers the position it was last so each any call will start where the last one ended. And wrapping it in all makes sure it exits early as soon as one any is False.

At least performance-wise this should be faster than most other approaches. However at the cost of readability.


If you want to have it even faster than a solution based on map and itertools.repeat can be slightly faster:

from itertools import repeat

def check_map(it, num):
    return all(map(any, repeat(iter(it), num)))

Benchmarked against the other answers:

# 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
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download