2

假设我有一个迭代非常昂贵的数据结构,我需要根据某些标准将它的元素收集到列表中。

#fake data.  pretend it's hard to access
import random
slowStruct = range(30)
random.shuffle(slowStruct)

def check1(x):
    return x < 3

def check2(x):
    return x > 15

def check3(x):
    return x < 25 and x > 20

最简单的方法是使用列表推导。但这需要对结构进行 3 次迭代:

res1 = [node for node in slowStruct if check1(node)]
res2 = [node for node in slowStruct if check2(node)]
res3 = [node for node in slowStruct if check3(node)]

一种更快的方法是使用循环并附加到结果列表:

res1 = []
res2 = []
res3 = []
for node in slowStruct:
    if check1(node):
        res1.append(node)
    if check2(node):
        res2.append(node)
    if check3(node):
        res3.append(node)

是否有可以执行多个过滤器的函数式编程构造或习语,而只使用一次迭代?

我可以想象它看起来像:

res1, res2, res3 = multiFilter(preds=[check1, check2, check3], iterable=slowStruct)
4

2 回答 2

2

理解没有一种干净的方法。如果要循环,请使用循环。列表推导应该只列出一个列表。

如果您愿意使用循环,则可以封装它:

def multi_filter(predicates, iterable):
    bins = [[] for _ in predicates]
    for item in iterable:
        for predicate, bin in zip(predicates, bins):
            if predicate(item):
                bin.append(item)

    return bins
于 2013-09-27T20:11:41.907 回答
1

是否有可以执行多个过滤器的函数式编程构造或习语,而只使用一次迭代?

是的,你可以做这个纯粹的功能(虽然你会达到最大递归深度,因为 python 不允许最后一次调用消除)。下面的代码看起来很糟糕,纯粹是函数式的,只在可迭代对象上迭代一次(但每次迭代都会迭代所有条件,这是不可避免的):

#! /usr/bin/python3

slowStruct = [1,2,3,4,5,6,7,8,9,10]
conditions = [lambda x: x < 5,
      lambda x: x % 2,
      lambda x: x % 3]

multiFilter = lambda preds, iterable: (
    lambda f, preds, iterable: f (
        f,
        iterable,
        preds,
        [ [] for _ in preds]
        )
    ) (
        lambda f, l, cs, accs: f (
            f,
            l [1:],
            cs,
            [acc + (l [:1] if c (l [0] ) else [] )
                for acc, c in zip (accs, cs) ]
        ) if l else accs,
        preds,
        iterable
    )

print (multiFilter (conditions, slowStruct) )

注意事项:Python 不是为函数式编程而生的(参见 LCO)。PEP8 也无助于格式化功能代码。

致所有评论者:我不提倡这种编码风格,我只是想提供一个只使用一次迭代的功能实现(根据 OP 的要求)。


编辑:如果您考虑列表理解中的破坏性分配,可能不是纯粹的功能。

于 2013-09-27T22:56:21.833 回答