通过谓词过滤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的标准库中,有没有类似的功能呢?
我知道自己动手实现这个功能很简单,但我想找一种更标准的方法。
2 个回答
10
生成器和列表推导式比可链式函数更符合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]
131
你可以使用 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 或推导式,然后取第一个元素(如果有的话)就可以了。
这些方法如果找不到任何东西会报错
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]