使用reduce来缩短for循环

时间:2016-08-19 10:10:18

标签: python

从数组Ns,我想按如下方式派生一个数组multipliers

Ns = [3, 3, 6, 3]

multipliers = [0]*len(Ns)
multipliers[0] = 1
for n in range(1,len(Ns)):
    multipliers[n] = multipliers[n-1] * Ns[n-1]

生成的数组multipliers[1, 3, 9, 54]。我的直觉是,应该可以使用reduce或其他内置函数使这段代码更简洁,但我还没有看到如何。有什么想法吗?

4 个答案:

答案 0 :(得分:5)

您可以将itertools.accumulate与自定义累积功能一起使用(仅限Python 3,如果您想使用Python 2,则可以安装fn.py库(或类似)或使用文档):

In [10]: from itertools import accumulate

In [11]: import operator

In [12]: list(accumulate([3, 3, 6, 3], func=operator.mul))
Out[12]: [3, 9, 54, 162]

然后修复第一个和最后一个元素:

In [13]: l = list(accumulate([3, 3, 6, 3], func=operator.mul))

In [14]: [1] + l[:-1]
Out[14]: [1, 3, 9, 54]

答案 1 :(得分:3)

您可以使用accumulate在Python 2中模拟reduce(请参阅@ soon的答案)的行为。您必须自己管理列表。

from functools import reduce
Ns = [3, 3, 6, 3]
multipliers = reduce(lambda l, x: l + [l[-1] * x], Ns[:-1], [1])

答案 2 :(得分:2)

reduce只提供缩小过程的最终结果,因此如果您想要所有中间值,可以使用列表推导,如下所示:

>>> [reduce(lambda x,y:x*y, Ns[:i], 1) for i in range(len(Ns))]
[1, 3, 9, 54]

但这并不高效,因为它会逐渐减少每个子列表。

答案 3 :(得分:2)

正如我的评论和其他答案所提到的,在Python 3中使用itertools.accumulate很容易。但是,从您之前的问题看来,您使用的是Python 2。

在Python中,直接迭代列表而不是使用索引几乎总是更好。您的代码可以像这样重写。 (我已将您的列表名称更改为ns以符合PEP 8 style guide)。

ns = [3, 3, 6, 3]
multipliers = []
last = 1
for u in ns:
    multipliers.append(last)
    last *= u
print multipliers

<强>输出

[1, 3, 9, 54]

请注意,此代码在末尾执行额外的乘法运算,其结果不会附加到multipliers。这是一个更紧凑的替代品。它不是使用last变量,而是查找multipliers中的最后一个元素,效率略低,虽然它没有进行额外的乘法,但它需要在切片时创建一个新的列表ns

ns = [3, 3, 6, 3]
multipliers = [1]
for u in ns[:-1]:
    multipliers.append(u * multipliers[-1])
print multipliers