python中reduce函数的行为

时间:2017-06-12 19:17:30

标签: python reduce

我对reduce函数的行为感到困惑。

  • 在第一个例子中,我得到了预期的结果:(1-1 / 2)*(1-1 / 3)= 1/3

    >>> reduce(lambda x, y: (1 - 1.0/x) * (1 - 1.0/y), [2,3])
    0.33333333333333337
    
  • 在第二个例子中,我没有得到预期的结果:(1-1 / 2)*(1-1 / 3)*(1-1 / 5)= 0.2666666

    >>> reduce(lambda x, y: (1 - 1.0/x) * (1 - 1.0/y), [2,3,5])
    -1.5999999999999996
    

有人可以解释一下我缺少的东西吗?

4 个答案:

答案 0 :(得分:11)

您需要的是mapreduce

>>> from functools import reduce
>>> yourlist = [2, 3]
>>> reduce(lambda x, y: x*y, map(lambda x: (1-1/x), yourlist))
0.33333333333333337

>>> yourlist = [2, 3, 5]
>>> reduce(lambda x, y: x*y, map(lambda x: (1-1/x), yourlist))
0.2666666666666667

因为地图会将每个项目转换为(1-1/item),然后reduce会将所有项目相乘。

补充说明:

您可以使用更快operator.mul代替lambda x, y: x * y,例如:

>>> import operator
>>> yourlist = [2, 3, 5]
>>> reduce(operator.mul, map(lambda x: (1-1/x), yourlist))
0.2666666666666667

感谢@acushner指出这一点(在评论中)。

您的功能出了什么问题

在这种情况下,实际上很容易看到什么不起作用,只需使用命名函数并添加一些print s:

def myfunc(x, y):
    print('x = {}'.format(x))
    print('y = {}'.format(y))
    res = (1 - 1.0/x) * (1 - 1.0/y)
    print('res = {}'.format(res))
    return res

reduce(myfunc, [2, 3])
# x = 2
# y = 3
# res = 0.33333333333333337

reduce(myfunc, [2, 3, 5])
# x = 2
# y = 3
# res = 0.33333333333333337
# x = 0.33333333333333337
# y = 5
# res = -1.5999999999999996

因此它将最后一个结果用作“下一个”x值。这就是为什么它适用于长度为2的情况,但对于更多的元素,它根本不适用你想要的公式。

替代

您也可以使用简单的map循环,而不是使用reducefor。让它们更容易,并且大多数时候它们更易读(在某些情况下它比reduce更快)。

prod = 1
for item in yourlist:
    prod *= 1 - 1 / item
print(prod)

是的,而不是1行,它现在是4行,但很容易理解发生了什么(但可能有一些边缘情况,其行为不像reduce,例如对于空输入) 。

但我通常更喜欢简单的循环而不是复杂的reduce - 操作,但始终是YMMV。 :)

答案 1 :(得分:2)

编辑:我批准上面的地图/缩小答案。

要理解原因,请阅读:

  

https://docs.python.org/2/library/functions.html#reduce

递减递归使用2个参数调用列表中每个元素的函数:累加器(最后一次调用的值)和当前元素。

所以你得到:

(1 - 1.0/( (1 - 1.0/2) * (1 - 1.0/3) )) * (1 - 1.0/5)

使用:

reduce(lambda acc, x: (1 - 1.0/acc) * (1 - 1.0/x), [2,3,5])
>>-1.5999999999999996

答案 2 :(得分:2)

要添加为什么您得到-1.5999999999999996作为结果,为了完整性,我们可以使用https://docs.python.org/2/library/functions.html#reduce作为我们的指南进行计算:

第一次迭代(将23的前2个迭代器值作为xy):

(1 - 1.0 / 2) * (1 - 1.0 / 3)

变为:

0.5 * 0.6666666666666667

产生:

0.33333333333333337

然后我们使用0.33333333333333337继续我们的下一次迭代,将此结果作为x,将下一个迭代次数5作为y

因此,我们的第二次迭代将是:

(1 - 1.0 / 0.33333333333333337) * (1 - 1.0/5)

变为:

-1.9999999999999996 * 0.8

产生:

-1.5999999999999996

答案 3 :(得分:-1)

在您的第二个示例中,您有3个输入。你需要:

reduce(lambda x, y: (1 - 1.0/x) * (1 - 1.0/y)* (1 - 1.0/z),...