有没有函数式编程的方式将列表过滤成真和假?
假设你有一个列表 L
,你想根据某个布尔函数 P
把它分成两个列表。也就是说,你想要一个列表,里面是所有满足 P(l)
为真的元素,另一个列表则是 P(l)
为假的元素。
我可以用Python这样来实现:
def multifilter(pred,seq):
trues,falses = [],[]
for x in seq:
if pred(x):
trues.append(x)
else:
falses.append(x)
return trues,falses
我的问题是:有没有什么函数式编程的方法可以做到这一点?
5 个回答
2
trues = [x for x in seq if pred(x)]
falses = [x for x in seq if not pred(x)]
这就是函数式编程风格的最高境界,除非你想要更多的函数调用。
2
Hoogle 是一个很不错的工具。你可以输入一个函数的类型,然后查看所有符合这个类型的函数。在这个例子中,我们需要的输入是:一个类型为 a
的列表,以及一个接受 a
并返回布尔值的函数,输出则是一个包含两个 a
列表的元组。在 Haskell 的语法中,这个表达式是 (a -> Bool) -> [a] -> ([a], [a])
。从这里我们可以看到,相关的函数是 partition。实现如下:
partition p xs == (filter p xs, filter (not . p) xs)
在 Python 中:
partition = lambda p, xs: (filter(p, xs), filter(lambda f: not p(f), xs))
或者这个方法更快,但看起来有点丑,因为它是不对称的:
partition = lambda p, xs: (filter(p, xs), [z for z in xs if not p(z)])
不过,这个方法确实做了两倍于你需要的计算,但我觉得如果你不使用变异(即不改变原数据),你就得这样做。
8
来自itertools的示例:
from itertools import tee, filterfalse
def partition(pred, iterable):
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)