问题:在与谓词匹配的序列中查找第一个元素
我想要一种惯用的方式来找到与谓词匹配的列表中的第一个元素。
当前代码非常丑陋:
[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
但是,如果已经有内置的插件开始用这样的实用函数填充代码,这是很鸡肋的(人们可能不会注意到它们已经在那里,因此随着时间的推移它们会不断重复出现)。
回答 0
要查找seq
与匹配的序列中的第一个元素predicate
:
next(x for x in seq if predicate(x))
或(itertools.ifilter
在Python 2上):
next(filter(predicate, seq))
StopIteration
如果没有,它将引发。
None
如果没有这样的元素,则返回:
next((x for x in seq if predicate(x)), None)
要么:
next(filter(predicate, seq), None)
回答 1
您可以使用具有默认值的生成器表达式,然后使用next
它:
next((x for x in seq if predicate(x)), None)
尽管对于这种单行代码,您需要使用Python> = 2.6。
这篇颇受欢迎的文章进一步讨论了这个问题:最干净的Python在列表中查找功能?。
回答 2
我认为您在问题中提出的两种解决方案都没有错。
在我自己的代码中,我会这样实现:
(x for x in seq if predicate(x)).next()
使用的语法可()
创建一个生成器,该生成器比使用一次生成所有列表的效率更高[]
。
回答 3
JF Sebastian的答案是最优雅的,但需要fortran指出的python 2.6。
对于2.6以下的Python版本,这是我能提供的最好的:
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()
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。