Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 查找序列中与谓词匹配的第一个元素_Python_Predicate - Fatal编程技术网

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”更容易阅读之外,这个问题还有一个更好的标题。