Find first element in a sequence that matches a predicate

Solution 1:

To find the first element in a sequence seq that matches a predicate:

next(x for x in seq if predicate(x))

Or simply:

Python 2:

next(itertools.ifilter(predicate, seq))

Python 3:

next(filter(predicate, seq))

These will raise a StopIteration exception if the predicate does not match for any element.


To return None if there is no such element:

next((x for x in seq if predicate(x)), None)

Or:

next(filter(predicate, seq), None)

Solution 2:

You could use a generator expression with a default value and then next it:

next((x for x in seq if predicate(x)), None)

Although for this one-liner you need to be using Python >= 2.6.

This rather popular article further discusses this issue: Cleanest Python find-in-list function?.

Solution 3:

I don't think there's anything wrong with either solutions you proposed in your question.

In my own code, I would implement it like this though:

(x for x in seq if predicate(x)).next()

The syntax with () creates a generator, which is more efficient than generating all the list at once with [].

Solution 4:

J.F. Sebastian's answer is most elegant but requires python 2.6 as fortran pointed out.

For Python version < 2.6, here's the best I can come up with:

from itertools import repeat,ifilter,chain
chain(ifilter(predicate,seq),repeat(None)).next()

Alternatively if you needed a list later (list handles the StopIteration), or you needed more than just the first but still not all, you can do it with islice:

from itertools import islice,ifilter
list(islice(ifilter(predicate,seq),1))

UPDATE: Although I am personally using a predefined function called first() that catches a StopIteration and returns None, Here's a possible improvement over the above example: avoid using filter / ifilter:

from itertools import islice,chain
chain((x for x in seq if predicate(x)),repeat(None)).next()