Pythonic方式在python中递归减少

时间:2018-04-12 09:09:50

标签: python reduce

在减少python中的列表时,我考虑过创建多列表缩减并编写以下代码段。

def multiply(a, b): return a * b

def recursive_reduce(reduce_func, *args):
     ret_val = reduce(reduce_func, *args)
     if type(ret_val) == list:
         ret_val = recursive_reduce(reduce_func, ret_val)
     return ret_val

a = [1, 1, 3]
b = [4, 5, 6]

recursive_reduce(multiply, a, b)

这很有效。但是我想知道根据返回值的类型定义迭代逻辑是否是pythonic。

我们是否有其他方式以更优雅的方式实现递归递减?

1 个答案:

答案 0 :(得分:3)

我认为你要做的是做一个递归版本的reduce。

def rreduce(f, init, default=None):                     
    if default is None:
        default = init[0]
        init = init[1:]
    if len(init) == 0:
         return default
    return rreduce(f, init[1:], f(default, init[0]))


>>> rreduce(lambda a, b: a*b, range(1,10))
362880
>>> rreduce(lambda a, b: a+b, ['t', 'a', 'c', 'o'])
'taco'

虽然递归很棒,但这不是Python reduce类型函数的首选方法,因为它很慢,你会遇到 STACK OVERFLOW (HAA)

>>> rreduce(lambda a, b: a + [b], list(range(1, 10000)), [])
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
<ipython-input-41-7dc07c5d9246> in <module>()
----> 1 rreduce(lambda a, b: a + [b], list(range(1, 10000)), [])

<ipython-input-33-37206eb8e39f> in rreduce(f, init, default)
      5     if len(init) == 0:
      6         return default
----> 7     return rreduce(f, init[1:], f(default, init[0]))

... last 1 frames repeated, from the frame below ...

<ipython-input-33-37206eb8e39f> in rreduce(f, init, default)
      5     if len(init) == 0:
      6         return default
----> 7     return rreduce(f, init[1:], f(default, init[0]))

RecursionError: maximum recursion depth exceeded in comparison

回答你的实际问题......

def lreduce(f, init, default=None):
        if default is None:
            return reduce(lambda x, a: x + [reduce(f, a)], init, [])
        else:
            return reduce(lambda x, a: x + [reduce(f, a, default)], init, [])

reduce列表列表。

>>> lreduce(lambda a, b: a + b, [range(10), range(10), range(10)])
[45, 45, 45]

if/else之所以必要,是因为reduce作为builtin不接受关键字参数:

In [56]: reduce(function=lambda a, b: a + b, sequence=range(10), initial=0)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-56-9fa3ed177831> in <module>()
----> 1 reduce(function=lambda a, b: a + b, sequence=range(10), initial=0)

TypeError: reduce() takes no keyword arguments

然后如果你想再往前走一步......

def lreduceall(f, init, default=None):
    if default is None:
        return reduce(f, reduce(lambda x, a: x + [reduce(f, a)], init, []))
    else:
        return reduce(f, reduce(lambda x, a: x + [reduce(f, a, default)], init, []), default)

最后:

>>> lreduceall(lambda a, b: a + b, [range(10), range(10), range(10)])
135