在单次迭代期间应用多个自包含过滤器

时间:2013-09-27 20:10:01

标签: python filter functional-programming

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

#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)

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

  

是否有可以执行的功能编程结构或习惯用法   多个过滤器,只使用一次迭代?

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

#! /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) )

Nota bene:Python不是用于函数式编程(参见LCO)。此外,PEP8无法格式化功能代码。

对于所有评论者:我不提倡这种编码风格,我只是试图给出一个只使用一次迭代的功能实现(按照OP的要求)。


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