我想从匹配条件的列表中获得第一项。产生的方法不能处理整个列表,这一点很重要,因为列表可能相当大。例如,以下函数就足够了:

def first(the_iterable, condition = lambda x: True):
    for i in the_iterable:
        if condition(i):
            return i

这个函数可以这样使用:

>>> first(range(10))
0
>>> first(range(10), lambda i: i > 3)
4

但是,我想不出一个好的内置/单行程序来让我这样做。如果没有必要,我不想复制这个函数。是否有一种内置的方法来获取匹配条件的第一项?


当前回答

该死的例外!

我喜欢Alex Martelli的回答。然而,由于next()在没有项目时抛出StopIteration异常, 我会使用下面的代码片段来避免异常:

a = []
item = next((x for x in a), None)

例如,

a = []
item = next(x for x in a)

将引发StopIteration异常;

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

其他回答

itertools模块包含一个用于迭代器的过滤器函数。过滤迭代器的第一个元素可以通过调用next()来获得:

from itertools import ifilter

print ifilter((lambda i: i > 3), range(10)).next()

类似于使用filter,你可以使用生成器表达式:

>>> (x for x in xrange(10) if x > 5).next()
6

在任何一种情况下,您都可能希望捕获StopIteration,以防没有元素满足您的条件。

从技术上讲,我认为你可以这样做:

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

它将避免必须进行try/except块。但这看起来有点模糊和滥用语法。

我会这样写

next(x for x in xrange(10) if x > 3)

Oneliner:

thefirst = [i for i in range(10) if i > 3][0]

如果你不确定根据条件,任何元素都是有效的,你应该用try/except将其括起来,因为[0]可能引发IndexError。

该死的例外!

我喜欢Alex Martelli的回答。然而,由于next()在没有项目时抛出StopIteration异常, 我会使用下面的代码片段来避免异常:

a = []
item = next((x for x in a), None)

例如,

a = []
item = next(x for x in a)

将引发StopIteration异常;

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration