clever any() like function to check if at least n elements are True?
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Melt
--
Chapters
00:00 Clever Any() Like Function To Check If At Least N Elements Are True?
00:38 Accepted Answer Score 14
01:42 Answer 2 Score 3
01:50 Answer 3 Score 0
02:08 Answer 4 Score 4
02:24 Thank you
--
Full question
https://stackoverflow.com/questions/4251...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #python3x #builtin
#avk47
ACCEPTED ANSWER
Score 14
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
ANSWER 2
Score 4
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
ANSWER 3
Score 3
Use sum:
sum(l) >= 2
# True
ANSWER 4
Score 0
Presumably any goes through the iterable until it finds a element that is True, and then stops.
Your solution scans all of the elements to see if there are at least 2. Instead, it should stop scanning as soon as it finds a second True element.