减少功能如何工作?

时间:2012-02-02 07:59:04

标签: python reduce

据我了解,reduce函数采用列表l和函数f。然后,它在列表的前两个元素上调用函数f,然后使用下一个列表元素和前一个结果重复调用函数f

所以,我定义了以下功能:

以下函数计算阶乘。

def fact(n):
    if n == 0 or n == 1:
        return 1
    return fact(n-1) * n


def reduce_func(x,y):
    return fact(x) * fact(y)

lst = [1, 3, 1]
print reduce(reduce_func, lst)

现在,这不应该给我((1! * 3!) * 1!) = 6吗?但是,它给出了720。为什么720?它似乎也采用6的阶乘。但是,我需要理解为什么。

有人可以解释为什么会发生这种情况并解决问题吗?

我基本上想要计算列表中所有条目的阶乘的乘积。 备份计划是运行循环并计算它。但是,我更喜欢使用reduce。

9 个答案:

答案 0 :(得分:66)

其他答案很棒。我只想添加一个插图示例,我觉得很好理解reduce()

>>> reduce(lambda x,y: x+y, [47,11,42,13])
113

的计算方法如下:

enter image description here

Source)(mirror

答案 1 :(得分:30)

理解 reduce()的最简单方法是查看其纯Python等效代码:

def myreduce(func, iterable, start=None):
    it = iter(iterable)
    if start is None:
        try:
            start = next(it)
        except StopIteration:
            raise TypeError('reduce() of empty sequence with no initial value')
    accum_value = start
    for x in iterable:
        accum_value = func(accum_value, x)
    return accum_value

你可以看到,只有你的reduce_func()才能将factorial应用到最右边的参数:

def fact(n):
    if n == 0 or n == 1:
        return 1
    return fact(n-1) * n

def reduce_func(x,y):
    return x * fact(y)

lst = [1, 3, 1]
print reduce(reduce_func, lst)

使用这个小修订版,代码会按预期产生 6 : - )

答案 2 :(得分:10)

您的函数在两个参数上调用fact()。您正在计算((1! * 3!)! * 1!)。解决方法是仅在第二个参数上调用它,并将reduce()初始值传递给。

答案 3 :(得分:9)

来自Python reduce documentation

  

reduce(function,sequence)返回一个单独的值,该值是通过在序列的前两个项上调用(binary)函数构建的,然后是结果和下一个项,依此类推。

所以,踩过去。它计算前两个元素reduce_func中的reduce_func(1, 3) = 1! * 3! = 6。然后,它计算结果的reduce_func和下一个项目:reduce_func(6, 1) = 6! * 1! = 720

你错过了,当第一个reduce_func调用的结果作为输入传递给第二个时,它在乘法之前被因子化。

答案 4 :(得分:2)

好的,明白了:

我需要先将数字映射到它们的阶乘,然后使用乘法运算符调用reduce。

所以,这样可行:

lst_fact = map(fact, lst)
reduce(operator.mul, lst_fact)

答案 5 :(得分:0)

嗯,首先,你的reduce_func没有折叠的结构;它与折叠的描述不符(这是正确的。)

折叠的结构是:def foldl(func, start, iter): return func(start, foldl(func, next(iter), iter)

现在,您的fact函数无法对两个元素进行操作 - 它只是计算阶乘。

所以,总而言之,你没有使用折叠,并且使用阶乘的定义,你不需要。

如果您确实想要使用阶乘,请查看y-combinator:http://mvanier.livejournal.com/2897.html

如果您想了解折叠,请查看我对此问题的回答,该问题证明了它用于计算累积分数:creating cumulative percentage from a dictionary of data

答案 6 :(得分:0)

您还可以使用reduce实现阶乘。

def factorial(n):
  return(reduce(lambda x,y:x*y,range(n+1)[1:]))

答案 7 :(得分:0)

Reduce通过参数#2中的迭代器提供的值连续执行参数#1中的函数

print '-------------- Example: Reduce(x + y) --------------'

def add(x,y): return x+y
x = 5
y = 10

import functools
tot = functools.reduce(add, range(5, 10))
print 'reduce('+str(x)+','+str(y)+')=' ,tot

def myreduce(a,b):
    tot = 0
    for i in range(a,b):
        tot = tot+i
        print i,tot
    print 'myreduce('+str(a)+','+str(b)+')=' ,tot

myreduce(x,y)

print '-------------- Example: Reduce(x * y) --------------'

def add(x,y): return x*y
x = 5
y = 10

import functools
tot = functools.reduce(add, range(5, 10))
print 'reduce('+str(x)+','+str(y)+')=' ,tot

def myreduce(a,b):
    tot = 1
    for i in range(a,b):
        tot = tot * i
        print i,tot
    print 'myreduce('+str(a)+','+str(b)+')=' ,tot

myreduce(x,y)

答案 8 :(得分:0)

除了这些简单的例子,这里还有一个我发现reduce实际上非常有用的例子:

想象一个有序的int值的可迭代值,通常带有一些连续的值,并且我们想将其“概括”为表示范围的元组列表。 (还要注意,此可迭代项可能是很长序列的生成器,这是使用reduce的另一个原因,而不是对内存集合的某些操作。)

from functools import reduce

def rle(a, b):
    if a and a[-1][1] == b:
        return a[:-1] + [(a[-1][0], b + 1)]
    return a + [(b, b + 1)]

reduce(rle, [0, 1, 2, 5, 8, 9], [])
# [(0, 3), (5, 6), (8, 10)]

请注意,initial使用了正确的[]值(此处为reduce)。

还处理了一些角案件:

reduce(rle, [], [])
# []

reduce(rle, [0], [])
# [(0, 1)]