查找与谓词匹配的序列中的第一个元素

时间:2011-12-16 12:36:46

标签: python predicate

我想要一种惯用的方法来查找列表中与谓词匹配的第一个元素。

目前的代码非常难看:

[x for x in seq if predicate(x)][0]

我考虑将其更改为:

from itertools import dropwhile
dropwhile(lambda x: not predicate(x), seq).next()

但是必须有更优雅的东西......如果它返回None值而不是在没有找到匹配时引发异常,那将会很好。

我知道我可以定义一个类似的函数:

def get_first(predicate, seq):
    for i in seq:
        if predicate(i): return i
    return None

但是开始使用这样的实用程序函数填充代码是非常无味的(并且人们可能不会注意到它们已经存在,所以如果有已经提供相同的内置函数,它们会随着时间的推移而重复)

4 个答案:

答案 0 :(得分:197)

next(x for x in seq if predicate(x))

如果没有,则会引发StopIteration

next(ifilter(predicate, seq), None)

如果没有这样的元素,

返回None

答案 1 :(得分:83)

您可以使用具有默认值的生成器表达式,然后使用next它:

next((x for x in seq if predicate(x)), None)

虽然对于这个单行,你需要使用Python> = 2.6。

这篇颇受欢迎的文章进一步讨论了这个问题:Cleanest Python find-in-list function?

答案 2 :(得分:5)

我认为您在问题中提出的任何解决方案都没有任何问题。

在我自己的代码中,我会像这样实现它:

(x for x in seq if predicate(x)).next()

使用()的语法会创建一个生成器,这比使用[]一次生成所有列表更有效。

答案 3 :(得分:1)

J.F。塞巴斯蒂安的答案是最优雅的,但需要python 2.6,就像他指出的那样。

对于Python版本< 2.6,这是我能想到的最好的:

from itertools import repeat,ifilter,chain
chain(ifilter(predicate,seq),repeat(None)).next()

或者,如果您稍后需要列表(列表处理StopIteration),或者您需要的不仅仅是第一个但仍然不是全部,您可以使用islice:

from itertools import islice,ifilter
list(islice(ifilter(predicate,seq),1))

更新: 虽然我个人使用名为first()的预定义函数捕获StopIteration并返回None,但这可能是对上述示例的改进:避免使用filter / ifilter:

from itertools import islice,chain
chain((x for x in seq if predicate(x)),repeat(None)).next()