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

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

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


当前回答

Python 3中最有效的方法是以下方法之一(使用类似的示例):

“理解”风格:

next(i for i in range(100000000) if i == 1000)

警告:该表达式也适用于Python 2,但在本例中使用的range在Python 3中返回一个可迭代对象,而不是像Python 2那样返回一个列表(如果你想在Python 2中构造一个可迭代对象,则使用xrange代替)。

注意,表达式避免在理解表达式next([i for…])中构造一个列表,这将导致在筛选元素之前创建一个包含所有元素的列表,并将导致处理整个选项,而不是在i == 1000时停止迭代。

具有“功能性”风格:

next(filter(lambda i: i == 1000, range(100000000)))

警告:这在Python 2中不起作用,甚至用xrange替换range,因为过滤器创建了一个列表而不是迭代器(效率低),下一个函数只适用于迭代器。

默认值

正如在其他响应中提到的那样,如果希望避免在条件不满足时引发异常,则必须向接下来的函数添加一个额外参数。

“功能性”风格:

next(filter(lambda i: i == 1000, range(100000000)), False)

“理解”风格:

使用这种风格,你需要用()包围理解表达式,以避免SyntaxError:如果不是唯一的参数,生成器表达式必须用圆括号括起来:

next((i for i in range(100000000) if i == 1000), False)

其他回答

这个问题已经有了很好的答案。我只是说说我的意见,因为我来这里是想为我自己的问题找到一个解决方案,这和OP非常相似。

如果你想使用生成器找到匹配条件的第一项的INDEX,你可以简单地这样做:

next(index for index, value in enumerate(iterable) if condition)

Oneliner:

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

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

我会这样写

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

对于不存在下一个内置的旧版本的Python:

(x for x in range(10) if x > 3).next()

我知道已经太迟了,但我的回答是:

def find_index(nums, fn):
    return next(i for i, x in enumerate(nums) if fn(x))
print(find_index([1, 2, 3, 4], lambda n: n % 2 == 1))