简体   繁体   English

使用reduce缩短for循环

[英]Using reduce to shorten a for-loop

From an array Ns , I'd like to derive an array multipliers as follows: 我想从数组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]

The resulting array multipliers is [1, 3, 9, 54] . 结果数组multipliers[1, 3, 9, 54] My gut feeling is that it should be possible to make this code more succinct using reduce or another built-in function, but I don't yet see how. 我的直觉是应该可以使用reduce或其他内置函数使此代码更简洁,但我还没有看到。 Any ideas? 有任何想法吗?

You could use itertools.accumulate with a custom accumulation function (Python 3 only, if you want to use Python 2 you could install fn.py library (or similar) or backport the function using the implementation provided in the docs) : 您可以将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]

And then just fix the first and the last elements: 然后只需修复第一个和最后一个元素:

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

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

You can simulate the behavior of accumulate (see @soon's answer) in Python 2 with reduce . 您可以使用reduce来模拟Python 2中accumulate的行为(请参阅@soon的答案)。 You have to manage the list by yourself. 您必须自己管理列表。

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

reduce give you just the final result of the reducing process, so if you want all the intermediate values you can use list comprehension as followed: reduce给您减少过程的最终结果,因此,如果您需要所有中间值,则可以按照以下方式使用列表推导:

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

but that isn't efficient since it reducing again and again for each sublist. 但这并不高效,因为它会针对每个子列表一次又一次地减少。

As my comment and other answers mention, this is easy in Python 3, using itertools.accumulate . 正如我的评论和其他答案所提到的,在Python 3中,使用itertools.accumulate很容易。 However, from your previous questions it appears that you're using Python 2. 但是,从先前的问题来看,您似乎正在使用Python 2。

In Python, it's almost always better to iterate directly over a list rather than using indices. 在Python中,直接遍历列表而不是使用索引通常总是更好。 Your code could be rewritten like this. 您的代码可以这样重写。 (I've changed your list name to ns to comply with the PEP 8 style guide ). (为了符合PEP 8样式指南,我已将您的列表名称更改为ns )。

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

output 输出

[1, 3, 9, 54]

Note that this code does an extra multiplication at the end, the result of which doesn't get appended to multipliers . 请注意,此代码在末尾进行了额外的乘法运算,其结果不会附加到multipliers Here's an alternative that's a little more compact. 这是一个更紧凑的选择。 Instead of using the last variable it looks up the last element in multipliers , which is slightly less efficient, and while it doesn't do that extra multiplication it does need to create a new list when it slices ns . 而不是使用last变量,而是在multipliers查找最后一个元素,后者的效率稍低,尽管它没有执行额外的乘法运算,但在对ns切片时确实需要创建一个新列表。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM