I would like to get the first item from a list matching a condition. It's important that the resulting method not process the entire list, which could be quite large. For example, the following function is adequate:
def first(the_iterable, condition = lambda x: True):
for i in the_iterable:
if condition(i):
return i
This function could be used something like this:
>>> first(range(10))
0
>>> first(range(10), lambda i: i > 3)
4
However, I can't think of a good built-in / one-liner to let me do this. I don't particularly want to copy this function around if I don't have to. Is there a built-in way to get the first item matching a condition?
In Python 2.6 or better:
If you want
StopIteration
to be raised if no matching element is found:next(x for x in the_iterable if x > 3)
If you want
default_value
(e.g.None
) to be returned instead:next( (x for x in the_iterable if x>3), default_value)
Note that you need an extra pair of parentheses around the generator expression in this case - they are needed always when the generator expression isn't the only argument.
I see most answers resolutely ignore the
next
built-in and so I assume that for some mysterious reason they're 100% focused on versions 2.5 and older -- without mentioning the Python-version issue (but then I don't see that mention in the answers that do mention thenext
built-in, which is why I thought it necessary to provide an answer myself -- at least the "correct version" issue gets on record this way;-).In 2.5, the
.next()
method of iterators immediately raisesStopIteration
if the iterator immediately finishes -- i.e., for your use case, if no item in the iterable satisfies the condition. If you don't care (i.e., you know there must be at least one satisfactory item) then just use.next()
(best on a genexp, line for thenext
built-in in Python 2.6 and better).If you do care, wrapping things in a function as you had first indicated in your Q seems best, and while the function implementation you proposed is just fine, you could alternatively use
itertools
, afor...: break
loop, or a genexp, or atry/except StopIteration
as the function's body, as various answers suggested. There's not much added value in any of these alternatives so I'd go for the starkly-simple version you first proposed.The
itertools
module contains a filter function for iterators. The first element of the filtered iterator can be obtained by callingnext()
on it:For older versions of Python where the next built-in doesn't exist:
As a reusable, documented and tested function
This question already has great answers. I'm only adding my two cents because I landed here trying to find a solution to my own problem, which is very similar to the OP.
If you want to find the INDEX of the first item matching a criteria using generators, you can simply do:
By using
one can check the condition of the value of the first item in the_iterable, and obtain its index without the need to evaluate all of the items in the_iterable.
The complete expression to use is
Here first_index assumes the value of the first value identified in the expression discussed above.