2011-12-16 97 views
110

前面的愚蠢问题:我想要一种习惯方式来查找列表中与谓词相匹配的第一个元素。找到与谓词相匹配的序列中的第一个元素

当前的代码是相当难看:

[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 

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

+1

这不是一个愚蠢的问题,而@ j-f-sebastian:这不是重复的。这个问题具体是关于返回一个对象,并返回`None`而不是抛出异常。这也是关于优雅。另一个问题更多的是一个问题,并没有提出这些问题,至少不是很清楚。 – 2017-03-06 16:05:30

+1

除了被后来问不是“[蟒蛇序列查找功能(https://stackoverflow.com/questions/6039425/python-sequence-find-function)”,这个问题有一个**更好的标题**。 – Wolf 2017-07-20 10:23:19

回答

159

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

它提出StopIteration如果是没有的。

next(ifilter(predicate, seq), None)

返回None如果不存在这样的元件。

+12

或者你可以为`next`提供第二个“default”参数,而不是引发异常。 – 2011-12-16 12:50:27

+2

@fortran:[`下一个()`](http://docs.python.org/library/functions.html#next)可因为Python 2.6,您可以阅读[最新消息页面(HTTP://文档。 python.org/whatsnew/2.7.html)快速熟悉新功能。 – jfs 2011-12-16 13:02:10

68

你可以使用一个发电机表达默认值,然后next它:

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

虽然这一个班轮你需要使用Python> = 2.6。

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

3

我不认为在你的问题中提出的解决方案有什么问题。

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

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

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

1

J.F.塞巴斯蒂安的答案是最优雅的,但需要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)) 

UPDATE: 虽然我个人使用)第一(称为预定义的函数,捕捉一个StopIteration和返回None,这里的一个可能的改进在上述的例子:避免使用滤波器/的IFilter:

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