26

I have a function. matchCondition(a), which takes an integer and either returns True or False.

I have a list of 10 integers. I want to return the first item in the list (in the same order as the original list) that has matchCondition returning True.

As pythonically as possible.

user1008636
  • 2,989
  • 11
  • 31
  • 45

2 Answers2

61
next(x for x in lst if matchCondition(x)) 

should work, but it will raise StopIteration if none of the elements in the list match. You can suppress that by supplying a second argument to next:

next((x for x in lst if matchCondition(x)), None)

which will return None if nothing matches.

Demo:

>>> next(x for x in range(10) if x == 7)  #This is a silly way to write 7 ...
7
>>> next(x for x in range(10) if x == 11)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> next((x for x in range(10) if x == 7), None)
7
>>> print next((x for x in range(10) if x == 11), None)
None

Finally, just for completeness, if you want all the items that match in the list, that is what the builtin filter function is for:

all_matching = filter(matchCondition,lst)

In python2.x, this returns a list, but in python3.x, it returns an iterable object.

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 2
    Interesting application of `next`, I never would have thought of it. – Mark Ransom Jan 16 '13 at 20:02
  • @MarkRansom -- It's an idiom that I picked up around here once upon a time and for whatever reason I've never let it go. As a side note, the performance of generator expressions i've found to be pretty poor. For small lists you don't gain any benefit from the short circuiting...i.e. `[x for x in lst if matchCondition(x)][0]` is *probably* faster in a lot of applications (or the corresponding expression using `filter`, but that's not python2 python3 compatible ... – mgilson Jan 16 '13 at 20:04
  • But to make it safe in the case of no matching results you would need `([x for x in lst if matchCondition(x)] or [None])[0]` which is really ugly. – Mark Ransom Jan 16 '13 at 20:07
  • @MarkRansom -- Never even thought of doing it that way, but I agree -- That's not the way to go and performance isn't everything (hence my answer). I just figured that it should be documented *somewhere* that this isn't always the best performing variation of this answer. – mgilson Jan 16 '13 at 20:13
5

Use the break statement:

for x in lis:
  if matchCondition(x):
     print x
     break            #condition met now break out of the loop

now x contains the item you wanted.

proof:

>>> for x in xrange(10):
   ....:     if x==5:
   ....:         break
   ....:         

>>> x
>>> 5
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504