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

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

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


当前回答

通过使用

(index for index, value in enumerate(the_iterable) if condition(value))

可以检查the_iterable中第一项的值的条件,并获得它的索引,而不需要计算the_iterable中的所有项。

要使用的完整表达式是

first_index = next(index for index, value in enumerate(the_iterable) if condition(value))

这里first_index假设上面讨论的表达式中标识的第一个值的值。

其他回答

类似于使用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(),你可以使用unpacking:

>>> a, *_ = filter(lambda e: e == 10, [7,8,9,10,11,12])
>>> a
10
>>> _
[]
>>> a, *_ = filter(lambda e: e == 1000, [7,8,9,10,11,12])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected at least 1, got 0)

注意,使用filter()相当于写入Python Docs (item for item in iterable if condition)。

如果你需要对边缘情况的支持,你可以这样写:

>>> a, *_ = [e for e in [7,8,9,10,11,12] if e == 1000] or [None]
>>> a
None
>>> _
[]

我会这样写

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

下面是带有基准的3个备选方案。

使用next ()

一行程序:

values = list(range(1, 10000000))

value = next((x for x in values if x > 9999999), None)

使用函数

这是使用函数next()的替代方案,它大约快2%-5%:

values = list(range(1, 10000000))

def first(items):
    for item in items:
        if item > 9999999:  # Your condition
            return item
    return None  # Default value

value = first(values)

使用λ

这是一个在所有情况下都可用于替换next()的函数。性能大约降低300%:

values = list(range(1, 10000000))

def first(items, condition, default = None):
    for item in items:
        if condition(item):
            return item
    return default

value = first(values, lambda x: x > 9999999, None)

基准

功能:1 x 下:1.02 - 1.05 x Lambda: > 3x

内存消耗相同。

这就是基准。

对于任何使用Python 3.8或更新版本的人,我建议使用PEP 572—赋值表达式中描述的“赋值表达式”。

if any((match := i) > 3 for i in range(10)):
    print(match)