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

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(),你可以使用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()不是最快的方法。

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

该死的例外!

我喜欢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

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

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

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

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

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))

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