查找与谓词[复制]相匹配的序列中的第一个元素

时间:2022-07-16 21:58:48

This question already has an answer here:

这个问题已经有了答案:

Stupid question ahead: I want an idiomatic way to find the first element in a list that matches a predicate.

前面有一个愚蠢的问题:我想要一种惯用的方法来找到匹配谓词的列表中的第一个元素。

The current code is quite ugly:

目前的代码相当难看:

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

I've thought about changing it to:

我想过把它改成:

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

But there must be something more elegant... And it would be nice if it returns a None value rather than raise an exception if no match is found.

但一定有更优雅的东西……如果它返回一个None值,而不是在没有找到匹配时引发异常,那就更好了。

I know I could just define a function like:

我知道我可以定义一个函数

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

But it is quite tasteless to start filling the code with utility functions like this (and people will probably not notice that they are already there, so they tend to be repeated over time) if there are built ins that already provide the same.

但是,如果代码中已经构建了这样的功能(而且人们可能不会注意到它们已经存在,因此随着时间的推移它们往往会被重复),那么开始在代码中填充这样的实用功能是非常乏味的。

4 个解决方案

#1


167  

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

接下来(seq if谓词(x)中的x表示x)

It raises StopIteration if there is none.

如果没有停止迭代,就会引发停止迭代。

next(ifilter(predicate, seq), None)

下(ifilter(谓词,seq),也没有)

returns None if there is no such element.

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

#2


71  

You could use a generator expression with a default value and then next it:

您可以使用一个带有默认值的生成器表达式,然后在下一个:

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

Although for this one-liner you need to be using Python >= 2.6.

尽管对于这个一行程序,您需要使用Python >= 2.6。

This rather popular article further discusses this issue: Cleanest Python find-in-list function?.

这篇相当流行的文章进一步讨论了这个问题:最干净的Python查找列表函数?

#3


4  

I don't think there's anything wrong with either solutions you proposed in your question.

我认为你在问题中提出的两种解决方案都没有问题。

In my own code, I would implement it like this though:

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

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

The syntax with () creates a generator, which is more efficient than generating all the list at once with [].

带()的语法创建一个生成器,这比使用[]一次生成所有列表要高效。

#4


1  

J.F. Sebastian's answer is most elegant but requires python 2.6 as fortran pointed out.

正如fortran指出的,J.F. Sebastian的答案是最优雅的,但是需要python 2.6。

For Python version < 2.6, here's the best I can come up with:

对于Python版本< 2.6,以下是我能想到的最好的:

from itertools import repeat,ifilter,chain
chain(ifilter(predicate,seq),repeat(None)).next()

Alternatively if you needed a list later (list handles the StopIteration), or you needed more than just the first but still not all, you can do it with islice:

或者,如果您以后需要一个列表(list处理StopIteration),或者您需要的不仅仅是第一个但不是全部,您可以使用islice:

from itertools import islice,ifilter
list(islice(ifilter(predicate,seq),1))

UPDATE: Although I am personally using a predefined function called first() that catches a StopIteration and returns None, Here's a possible improvement over the above example: avoid using filter / ifilter:

更新:虽然我个人使用的是一个预定义函数first(),它捕获一个StopIteration并返回None,但与上面的示例相比,这里有一个可能的改进:避免使用filter / ifilter:

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

#1


167  

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

接下来(seq if谓词(x)中的x表示x)

It raises StopIteration if there is none.

如果没有停止迭代,就会引发停止迭代。

next(ifilter(predicate, seq), None)

下(ifilter(谓词,seq),也没有)

returns None if there is no such element.

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

#2


71  

You could use a generator expression with a default value and then next it:

您可以使用一个带有默认值的生成器表达式,然后在下一个:

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

Although for this one-liner you need to be using Python >= 2.6.

尽管对于这个一行程序,您需要使用Python >= 2.6。

This rather popular article further discusses this issue: Cleanest Python find-in-list function?.

这篇相当流行的文章进一步讨论了这个问题:最干净的Python查找列表函数?

#3


4  

I don't think there's anything wrong with either solutions you proposed in your question.

我认为你在问题中提出的两种解决方案都没有问题。

In my own code, I would implement it like this though:

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

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

The syntax with () creates a generator, which is more efficient than generating all the list at once with [].

带()的语法创建一个生成器,这比使用[]一次生成所有列表要高效。

#4


1  

J.F. Sebastian's answer is most elegant but requires python 2.6 as fortran pointed out.

正如fortran指出的,J.F. Sebastian的答案是最优雅的,但是需要python 2.6。

For Python version < 2.6, here's the best I can come up with:

对于Python版本< 2.6,以下是我能想到的最好的:

from itertools import repeat,ifilter,chain
chain(ifilter(predicate,seq),repeat(None)).next()

Alternatively if you needed a list later (list handles the StopIteration), or you needed more than just the first but still not all, you can do it with islice:

或者,如果您以后需要一个列表(list处理StopIteration),或者您需要的不仅仅是第一个但不是全部,您可以使用islice:

from itertools import islice,ifilter
list(islice(ifilter(predicate,seq),1))

UPDATE: Although I am personally using a predefined function called first() that catches a StopIteration and returns None, Here's a possible improvement over the above example: avoid using filter / ifilter:

更新:虽然我个人使用的是一个预定义函数first(),它捕获一个StopIteration并返回None,但与上面的示例相比,这里有一个可能的改进:避免使用filter / ifilter:

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