Python 查找序列中与谓词匹配的第一个元素
我想要一种惯用的方法来查找列表中与谓词匹配的第一个元素 目前的代码相当难看:Python 查找序列中与谓词匹配的第一个元素,python,predicate,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(pr
[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
但是,用这样的实用函数填充代码是非常乏味的(人们可能不会注意到它们已经存在,所以它们往往会随着时间的推移而重复)如果存在已提供相同功能的内置项。要在序列
seq
中查找与谓词匹配的第一个元素,请执行以下操作:
next(x for x in seq if predicate(x))
或者简单地说:
Python 2:
next(itertools.ifilter(predicate, seq))
next(filter(predicate, seq))
Python 3:
next(itertools.ifilter(predicate, seq))
next(filter(predicate, seq))
如果谓词与任何元素都不匹配,则会引发StopIteration
异常
如果没有此类元素,则返回None
:
next((x for x in seq if predicate(x)), None)
或:
您可以使用具有默认值的生成器表达式,然后使用它:
next((x for x in seq if predicate(x)), None)
尽管对于这一行程序,您需要使用Python>=2.6
这篇颇受欢迎的文章进一步讨论了这个问题:。我认为您在问题中提出的两种解决方案都没有任何问题
在我自己的代码中,我将实现如下:
(x for x in seq if predicate(x)).next()
使用()
的语法创建了一个生成器,它比使用[]
J.F.一次生成所有列表更高效。Sebastian的回答非常优雅,但正如fortran所指出的,它需要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()
或者,您可以为next
提供第二个“default”参数,以代替引发异常。@fortran:从Python 2.6开始提供,您可以通过阅读快速熟悉新功能。我是Python新手,阅读文档,ifilter使用“yield”方法。我假设这意味着谓词在执行过程中被惰性地计算。i、 我们不在整个列表中运行谓词,因为我有一个谓词函数,它有点昂贵,我只想迭代到找到item@geekazoid:seq.find(&method(:predicate))
或更简洁的实例方法,例如:[1,1,4]。find(&:even?)
ifilter
在Python3中被重命名为filter
。不仅如此-对于[]
,如果迭代器永不结束或其元素难以创建,您可能会遇到问题,如果迭代器越晚,它就会得到……'generator'对象在Python3上没有属性“next”
。@glglglglgl-至于第一点(永不结束)我对此表示怀疑,因为这个论点是一个有限的序列[更准确地说,根据OP的问题,是一个列表]。至于第二个:同样,由于提供的参数是一个序列,因此在调用此函数时,对象应该已经创建并存储了。。。。还是我遗漏了什么?@J.F.Sebastian-谢谢,我没有意识到这一点!:)出于好奇,这种选择背后的设计原则是什么?@mac-与其他特殊方法的双下划线保持一致。再见!如果归结到这一点,我只会做一个简单的“for”循环,循环中有一个“if”——除了比“if”更容易阅读之外,这个问题还有一个更好的标题。