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

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

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


当前回答

下面是三种方法的速度测试。Next()不是最快的方法。

from timeit import default_timer as timer

# Is set irreflexive?

def a():
    return frozenset((x3, x3) for x3 in set([x1[x2] for x2 in range(2) for x1 in value]) if (x3, x3) in value) == frozenset()


def b():
    return next((False for x1 in value if (x1[0], x1[0]) in value or (x1[1], x1[1]) in value), True)


def c():
    for x1 in value:
        if (x1[0], x1[0]) in value or (x1[1], x1[1]) in value:
            return False
    return True


times = 1000000
value = frozenset({(1, 3), (2, 1)})


start_time = timer()
for x in range(times):
    a()
print("a(): Calculation ended after " + str(round((timer() - start_time) * 1000) / 1000.0) + " sec")

start_time = timer()
for x in range(times):
    b()
print("b(): Calculation ended after " + str(round((timer() - start_time) * 1000) / 1000.0) + " sec")

start_time = timer()
for x in range(times):
    c()
print("c(): Calculation ended after " + str(round((timer() - start_time) * 1000) / 1000.0) + " sec")

结果:

Calculation ended after 1.365 sec
Calculation ended after 0.685 sec
Calculation ended after 0.493 sec

其他回答

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

from itertools import ifilter

print ifilter((lambda i: i > 3), range(10)).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))

下面是带有基准的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

内存消耗相同。

这就是基准。

类似于使用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块。但这看起来有点模糊和滥用语法。

作为一个可重用、文档化和测试的函数

def first(iterable, condition = lambda x: True):
    """
    Returns the first item in the `iterable` that
    satisfies the `condition`.

    If the condition is not given, returns the first item of
    the iterable.

    Raises `StopIteration` if no item satysfing the condition is found.

    >>> first( (1,2,3), condition=lambda x: x % 2 == 0)
    2
    >>> first(range(3, 100))
    3
    >>> first( () )
    Traceback (most recent call last):
    ...
    StopIteration
    """

    return next(x for x in iterable if condition(x))

带有默认参数的版本

@zorf建议这个函数的一个版本,如果可迭代对象为空或没有匹配条件的项,你可以有一个预定义的返回值:

def first(iterable, default = None, condition = lambda x: True):
    """
    Returns the first item in the `iterable` that
    satisfies the `condition`.

    If the condition is not given, returns the first item of
    the iterable.

    If the `default` argument is given and the iterable is empty,
    or if it has no items matching the condition, the `default` argument
    is returned if it matches the condition.

    The `default` argument being None is the same as it not being given.

    Raises `StopIteration` if no item satisfying the condition is found
    and default is not given or doesn't satisfy the condition.

    >>> first( (1,2,3), condition=lambda x: x % 2 == 0)
    2
    >>> first(range(3, 100))
    3
    >>> first( () )
    Traceback (most recent call last):
    ...
    StopIteration
    >>> first([], default=1)
    1
    >>> first([], default=1, condition=lambda x: x % 2 == 0)
    Traceback (most recent call last):
    ...
    StopIteration
    >>> first([1,3,5], default=1, condition=lambda x: x % 2 == 0)
    Traceback (most recent call last):
    ...
    StopIteration
    """

    try:
        return next(x for x in iterable if condition(x))
    except StopIteration:
        if default is not None and condition(default):
            return default
        else:
            raise