应用三参数函数“减少”列表的pythonic方法是啥?

Posted

技术标签:

【中文标题】应用三参数函数“减少”列表的pythonic方法是啥?【英文标题】: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

【问题讨论】:

【参考方案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

【讨论】:

以上是关于应用三参数函数“减少”列表的pythonic方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Python第四课----函数

三.Python函数

MySQL基础--存储过程和函数

Python基础语法

zip函数

Python全栈开发基础三