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

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

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


当前回答

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

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

其他回答

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

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

下面是三种方法的速度测试。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))

Python 2.6+和Python 3:

如果你想在没有找到匹配的元素时引发StopIteration:

next(x for x in the_iterable if x > 3)

如果你想要返回default_value(例如None):

next((x for x in the_iterable if x > 3), default_value)

注意,在这种情况下,在生成器表达式周围需要一对额外的圆括号-当生成器表达式不是唯一的参数时,就需要它们。

我看到大多数答案都坚决地忽略了下一个内置版本,所以我假设出于某种神秘的原因,他们100%专注于2.5及以上版本——没有提到python版本的问题(但我在回答中没有看到提到下一个内置版本的问题,这就是为什么我认为有必要自己提供一个答案——至少“正确版本”的问题会以这种方式记录下来;-)。

Python <= 2.5

如果迭代器立即结束,迭代器的.next()方法立即引发StopIteration——也就是说,对于您的用例,如果可迭代对象中没有项满足条件。如果你不在乎(也就是说,你知道至少有一个令人满意的项),那么只需使用.next()(最好用于genexp, Python 2.6或更好的下一个内置代码行)。

如果你真的关心,就像你在Q中第一次指出的那样,将东西包装在函数中似乎是最好的,而你提出的函数实现也很好,你可以选择使用itertools,一个for…: break循环,或genexp,或try/except StopIteration作为函数体,正如各种答案所建议的那样。这些替代方案都没有多少附加价值,所以我会选择你最初提出的极其简单的版本。