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

前面的愚蠢问题:我想要一个习惯的方式来find匹配谓词的列表中的第一个元素。

目前的代码是相当丑陋的:

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

我想过把它改成:

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

但是必须有更优雅的东西…如果它返回一个None值,而不是在没有find匹配的情况下抛出exception,那将会很好。

我知道我可以定义一个函数,如:

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

但是用这样的效用函数来开始填充代码是相当无味的(如果已经提供了相同的内置函数,人们可能不会注意到它们已经在那里,所以它们往往会随着时间的推移而重复)。

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

如果没有,则会引发StopIteration

next(ifilter(predicate, seq), None)

如果没有这样的元素,则返回None

你可以使用一个默认值的生成器expression式,然后next

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

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

这个颇受欢迎的文章进一步讨论了这个问题: 最干净的Python find-in-list函数? 。

我不认为你提出的解决scheme有什么问题。

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

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

()语法创build一个生成器,比用[]一次生成所有列表更有效率。

JF塞巴斯蒂安的答案是最优雅的,但要求python 2.6 fortran指出。

对于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()