有没有函数式编程的方式将列表过滤成真和假?

7 投票
5 回答
604 浏览
提问于 2025-04-16 04:03

假设你有一个列表 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)

撰写回答