【问题标题】:multiple self-contained filters applied during a single iteration在单次迭代期间应用多个自包含过滤器
【发布时间】:2013-10-04 06:03:44
【问题描述】:

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

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

【问题讨论】:

    标签: python filter functional-programming


    【解决方案1】:

    对于推导,没有一种干净的方式来做到这一点。如果要循环,请使用循环。列表推导应该只列出一个列表。

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

    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
    

    【讨论】:

    • 这是一个非常干净和简单的常见问题解决方案。我喜欢它。
    【解决方案2】:

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

    是的,您可以纯粹地执行此操作(尽管您会达到最大递归深度,因为 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 的要求)。


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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-04
      • 2020-12-23
      相关资源
      最近更新 更多