92

I would want to do something like:

>>> lst = [1, 2, 3, 4, 5]
>>> lst.find(lambda x: x % 2 == 0)
2
>>> lst.findall(lambda x: x % 2 == 0)
[2, 4]

Is there anything nearing such behavior in Python's standard libraries?

I know it's very easy to roll-your-own here, but I'm looking for a more standard way.

2 Answers 2

134

You can use the filter method:

>>> lst = [1, 2, 3, 4, 5]
>>> filter(lambda x: x % 2 == 0, lst)
[2, 4]

or a list comprehension:

>>> lst = [1, 2, 3, 4, 5]
>>> [x for x in lst if x %2 == 0]
[2, 4]

to find a single element, you could try:

>>> next(x for x in lst if x % 2 == 0)
2

Though that would throw an exception if nothing matches, so you'd probably want to wrap it in a try/catch. The () brackets make this a generator expression rather than a list comprehension.

Personally though I'd just use the regular filter/comprehension and take the first element (if there is one).

These raise an exception if nothing is found

filter(lambda x: x % 2 == 0, lst)[0]
[x for x in lst if x %2 == 0][0]

These return empty lists

filter(lambda x: x % 2 == 0, lst)[:1]
[x for x in lst if x %2 == 0][:1]
Sign up to request clarification or add additional context in comments.

6 Comments

Rather than a generator comprehension, you could also use itertools.ifilter(func, list).next() which is a little closer to the desired syntax.
You can also use itertools.dropwhile(lambda x: not func(x), list) which will not thrown an exception should the list contain no element that satisfies the predicate. It also has the advantage that it can short circuit should the desired element occur before the end of the list.
From the above, there is no suitable and simple function for this in the library. I prefer a simple for/if or a home-rolled utility function.
Surprising that this functionality doesn't exist. Is there some design reason why?
@AllenWang It's mainly due to Guido Van Rossum's preference and stylistic choices for Python, AFAICT. The creator of the language didn't think functional programming had much to provide for Python (c.f.: blog.finxter.com/about-guidos-fate-of-reduce-in-python-3000).
|
11

Generators and list comprehensions are more pythonic than chainable functions.

>>> lst = [i for i in range(1, 6)]

>>> lst
[1, 2, 3, 4, 5]

>>> gen = (x for x in lst if x % 10 == 0)

>>> next(gen, 'not_found')
'not_found'

>>> [x for x in gen]
[]

For example, I use it like this sometimes:

>>> n = next((x for x in lst if x % 10 == 0), None)
>>> if n is None:
...     print('Not found')
... 
Not found

Otherwise, you can define your utility function oneliners like this:

>>> find = lambda fun, lst: next((x for x in lst if fun(x)), None)
>>> find(lambda x: x % 10 == 0, lst)
>>> find(lambda x: x % 5 == 0, lst)
5

>>> findall = lambda fun, lst: [x for x in lst if fun(x)]
>>> findall(lambda x: x % 5 == 0, lst)
[5]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.