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.
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
L = [True, False, False, True]
This does only the needed iterations:
def many(iterable, n):
if n < 1:
return True
counter = 0
for x in iterable:
if x:
counter += 1
if counter == n:
return True
return False
Now:
>>> many(L, 2)
True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With