【问题标题】:Which is the pythonic way to 'reduce' a list applying a three-parameter function?应用三参数函数“减少”列表的pythonic方法是什么?
【发布时间】:2021-12-08 13:20:47
【问题描述】:

我已经习惯了类似 FP/haskell 的 reduce 概念,已经在 Python 中作为内置库实现:

from functools import reduce
lst = [1,2,3,4,5]
reduce(lambda x, y: x*y, lst)
# result: 120

但这不适用于例如具有三个参数的 lambda:

from functools import reduce
lst = [1,2,3,4,5]
reduce(lambda x, y, z: x*y+z, lst)
# expected result: (1*2+3) * 4 + 5
# actual result: 
#   TypeError: <lambda>() missing 1 required positional argument: 'z'

基本原理是保持“前一个结果是下一个参数”的规则。

是否有内置的实现,或功能结构的巧妙/简单组合来实现这样的目标?


ps。当心pseudo-duplicates

【问题讨论】:

    标签: python python-3.x functional-programming


    【解决方案1】:

    一个相当简单的实现是

    import inspect
    
    
    def nreduce(fn, lst):
        nargs = len(inspect.signature(fn).parameters)
        args = list(lst)
        while len(args) >= nargs:
            next_args = [args.pop(0) for x in range(nargs)]
            args.insert(0, fn(*next_args))
        return args
    
    
    lst = [1, 2, 3, 4, 5]
    print(nreduce(lambda x, y, z: x * y + z, lst))
    

    如果你想花哨,你可以使用deque 使刚刚减少的值更快地插入到列表的左侧:

    import collections
    
    def nreduce(fn, lst):
        nargs = len(inspect.signature(fn).parameters)
        arg_queue = collections.deque(lst)
        while len(arg_queue) >= nargs:
            next_args = [arg_queue.popleft() for x in range(nargs)]
            arg_queue.appendleft(fn(*next_args))
        return list(arg_queue)
    

    如果lst 的长度不能被fn 的元数整除,那么剩余的元素也会被返回。

    另一个实现,它可以与任何可迭代对象一起工作,而无需复制到其他列表或队列中(不会返回 lst 的其余部分,只是它消耗的值):

    def nreduce(fn, lst):
        nargs = len(inspect.signature(fn).parameters)
        lst_iter = iter(lst)
        next_args = []
        while True:
            try:
                while len(next_args) < nargs:
                    next_args.append(next(lst_iter))
            except StopIteration:
                break
            next_args = [fn(*next_args)]
        return next_args
    

    【讨论】:

      猜你喜欢
      • 2010-09-26
      • 2015-12-20
      • 2012-12-05
      • 1970-01-01
      • 2019-09-10
      • 1970-01-01
      • 2019-06-28
      • 1970-01-01
      • 2014-09-06
      相关资源
      最近更新 更多