hynek / first

The function you always missed in Python: return the first true value of an iterable.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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! :)