Add "first_n" function?
senpos opened this issue · comments
Hi @hynek,
What is your opinion on adding first_n
function into this library?
>>> seq = [None, 2, None, None, None, 5, None, None, 8]
>>> first_n(seq, 2)
[2, 5]
>>> first_n(range(10), 3, key=lambda x: x % 2 == 0)
[0, 2, 4]
It is convenient to expect such thing in this library.
Current readable alternative (Variant 1):
n = 3
seq = range(10)
result = []
for item in seq:
if len(result) == n:
break
if item % 2 == 0:
result.append(item)
# result = [0, 2, 4]
Not that readable alternative (Variant 2):
from itertools import islice
n = 3
seq = range(10)
list(islice(filter(lambda item: item % 2 == 0, seq), 0, n))
# [0, 2, 4]
There is also a fancy implementation from SO (Variant 3):
from itertools import count
n = 3
seq = range(10)
list(filter(lambda item, c=count(): item % 2 == 0 and next(c) < n, seq))
# [0, 2, 4]
As you can see, all of those alternatives above are ugly and it would be great to have a thing that is as natural as first
, but for n
elements.
As for possible implementation, I like the idea in variant 2:
def first_n(iterable, n, default=None, key=None):
result = list(islice(filter(key, iterable), 0, n))
if not result and default is not None:
return default
return result
- return result if it is non-falsy
- return default if result is falsy and default is given
- return empty list if result is falsy and no default is given
Examples:
>>> none_seq = [None, None, None]
>>> first_n(none_seq, 2)
[]
>>> first_n(none_seq, 2, default='default_value')
'default_value'
>>> seq2 = [None, None, 1, None, "hi", None, 2]
>>> first_n(seq2, 2)
[1, 'hi']
Please, let me know what you think. :)
I’m honestly not big on adding any features to first – how about you try to suggest it to be added to boltons where I’ve successfully smuggled first into?
Hi,
Got it. Will propose this function there.
Thanks for your time! :)