通过谓词过滤 Python 列表

我想做的是:

>>> lst = [1, 2, 3, 4, 5]
>>> lst.find(lambda x: x % 2 == 0)
2
>>> lst.findall(lambda x: x % 2 == 0)
[2, 4]

在 Python 的标准库中有类似的行为吗?

我知道在这里自己动手很容易但我想找一种更标准的方式。

93074 次浏览

您可以使用 filter 方法:

>>> lst = [1, 2, 3, 4, 5]
>>> filter(lambda x: x % 2 == 0, lst)
[2, 4]

或者列表内涵:

>>> lst = [1, 2, 3, 4, 5]
>>> [x for x in lst if x %2 == 0]
[2, 4]

要找到一个单一的元素,你可以试试:

>>> next(x for x in lst if x % 2 == 0)
2

不过,如果没有匹配,那将引发异常,因此您可能希望将其包装在 try/catch 中。括号使这个表达式成为一个生成器表达式而不是一个列表内涵。

就我个人而言,我会使用常规的过滤器/理解,并采用第一个元素(如果有的话)。

如果没有找到任何东西,则会引发异常

filter(lambda x: x % 2 == 0, lst)[0]
[x for x in lst if x %2 == 0][0]

这些返回空列表

filter(lambda x: x % 2 == 0, lst)[:1]
[x for x in lst if x %2 == 0][:1]

与可链式函数相比,生成器和列表理解更具 Python 特性。

>>> lst = [i for i in range(1, 6)]


>>> lst
[1, 2, 3, 4, 5]


>>> gen = (x for x in lst if x % 10 == 0)


>>> next(gen, 'not_found')
'not_found'


>>> [x for x in gen]
[]

例如,我有时会这样使用它:

>>> n = next((x for x in lst if x % 10 == 0), None)
>>> if n is None:
...     print('Not found')
...
Not found

否则,您可以像下面这样定义您的实用函数泛线:

>>> find = lambda fun, lst: next((x for x in lst if fun(x)), None)
>>> find(lambda x: x % 10 == 0, lst)
>>> find(lambda x: x % 5 == 0, lst)
5


>>> findall = lambda fun, lst: [x for x in lst if fun(x)]
>>> findall(lambda x: x % 5 == 0, lst)
[5]