据我了解,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。
答案 0 :(得分:66)
其他答案很棒。我只想添加一个插图示例,我觉得很好理解reduce()
:
>>> reduce(lambda x,y: x+y, [47,11,42,13])
113
的计算方法如下:
答案 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)]