从匹配条件的迭代中获取第一个项目

2022-01-10 00:00:00 python iterator

问题描述

我想从符合条件的列表中获取第一项.重要的是,生成的方法不处理整个列表,这可能非常大.例如,下面的函数就足够了:

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?


解决方案

在 Python 2.6+ 和 Python 3 中:

In Python 2.6+ and Python 3:

如果您希望在未找到匹配元素的情况下引发 StopIteration:

If you want StopIteration to be raised if no matching element is found:

next(x for x in the_iterable if x > 3)

如果您希望返回 default_value(例如 None):

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 whenever the generator expression isn't the only argument.

我看到大多数答案坚决忽略next 内置的,所以我假设出于某种神秘的原因,他们 100% 专注于 2.5 及更早版本 - 没有提及 Python 版本问题(但我没有在答案中看到 确实提到了内置的next,这就是为什么我认为有必要自己提供一个答案——至少正确的版本"问题会以这种方式记录下来;-).

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 the next 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;-).

在 2.5 中,.next() 如果迭代器立即完成,则迭代器的方法会立即引发 StopIteration —— 即,对于您的用例,如果迭代器中没有项目满足条件.如果您不关心(即,您知道 必须 至少有一个令人满意的项目),那么只需使用 .next() (最好在 genexp 上,行next 在 Python 2.6 及更高版本中内置).

In 2.5, the .next() method of iterators immediately raises StopIteration 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 the next built-in in Python 2.6 and better).

如果您确实在乎,最好按照您在 Q 中首先指出的那样将东西包装在一个函数中,虽然您提出的函数实现很好,但您也可以使用 itertools,一个 for...: break 循环,或一个 genexp,或一个 try/except StopIteration 作为函数的主体,正如各种答案所建议的那样.这些替代方案中的任何一个都没有太多附加值,所以我会选择您最初提出的极其简单的版本.

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, a for...: break loop, or a genexp, or a try/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.

相关文章