Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find first element in a sequence that matches a predicate in Python? [duplicate]

Possible Duplicate:
Python: find first element in a sequence that matches a predicate

Is there a higher order function in Python standard library that encapsulates the following control flow pattern?

>>> def find(pred, coll):
...   for x in coll:
...     if pred(x):
...       return x
... 
>>> find(lambda n : n % 2 == 0, [3, 5, 8, 9, 6])
8
>>> find(lambda n : n % 2 == 0, [3, 5, 7, 9, 6])
6
>>> find(lambda n : n % 2 == 0, [3, 5, 7, 9, 1])
like image 524
missingfaktor Avatar asked Dec 01 '22 22:12

missingfaktor


2 Answers

You can combine ifilter and islice to get just the first matching element.

>>> list(itertools.islice(itertools.ifilter(lambda n: n % 2 == 0, lst), 1))
[8]

However, I wouldn't consider this anyhow more readable or nicer than the original code you posted. Wrapped in a function it will be much nicer though. And since next only returns one element there is no need for islice anymore:

def find(pred, iterable):
    return next(itertools.ifilter(pred, iterable), None)

It returns None if no element was found.

However, you still have the rather slow call of the predicate function every loop. Please consider using a list comprehension or generator expression instead:

>>> next((x for x in lst if x % 2 == 0), None)
8
like image 56
ThiefMaster Avatar answered Dec 04 '22 09:12

ThiefMaster


itertools.ifilter() can do this, if you just grab the first element of the resulting iterable.

itertools.ifilter(pred, col1).next()

Similarly, so could a generator object (again, taking the first item out of the resulting generator):

(i for i in col1 if i % 2 == 0).next()

Since both of these are lazy-evaluated, you'll only evaluate as much of the input iterable as is necessary to get to the first element that satisfies the predicate. Note that if nothing matches the predicate, you'll get a StopIteration exception. You can avoid this by using the next() builtin instead:

next((i for i in col1 if i % 2 == 0), None)
like image 24
Amber Avatar answered Dec 04 '22 08:12

Amber