带有累加器的列表推导式

10

使用列表推导式(或另一种紧凑的方法),最佳方式是复制此简单函数的方法是什么?

import numpy as np

sum=0
array=[]
for i in np.random.rand(100):
   sum+=i
   array.append(sum)

1
我不会使用列表推导式 - 元素应该是彼此独立的,但在这种情况下它们并不是。 - Izkata
1
你为什么想把这个转换成列表推导式呢?将其保留在单独的循环中会更易读。也许可以将其改为 array = [0], for i in rand(100): array.append(i + array[-1]) - Martijn Pieters
1
这个跟 https://dev59.com/HmYs5IYBdhLWcg3wAfLO 一样吗? - doctorlove
rand() 函数在哪里声明?它不是内置函数。 - Hannes Ovrén
我没有在Python中追踪rand()函数。也许是Random.randint()?所以你想要一个随机大小的数组? - hyleaus
显示剩余4条评论
5个回答

11
在Python 3中,您需要使用itertools.accumulate()函数。
from itertools import accumulate

array = list(accumulate(rand(100)))

Accumulate可以计算一个可迭代对象中所有元素值的累积和,从第一个值开始:

>>> from itertools import accumulate
>>> list(accumulate(range(10)))
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]

作为第二个参数,您可以传入不同的操作;这应该是一个可调用函数,它接受累积结果和下一个值,并返回新的累积结果。 operator 模块 在提供此类工作的标准数学运算符方面非常有帮助;例如,您可以使用它来生成运行乘法结果:

>>> import operator
>>> list(accumulate(range(1, 10), operator.mul))
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880]

这个功能很容易迁移到旧版本(Python 2或Python 3.0或3.1):

# Python 3.1 or before

import operator

def accumulate(iterable, func=operator.add):
    'Return running totals'
    # accumulate([1,2,3,4,5]) --> 1 3 6 10 15
    # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
    it = iter(iterable)
    total = next(it)
    yield total
    for element in it:
        total = func(total, element)
        yield total

这个可以用,但我想要像IPython命令行上的列表推导那样紧凑易用的东西。 - Pierz
@Pierz:我在accumulate()迭代器上使用了list(),以便为您提供一个快速的值列表。您仍然可以在列表推导式中使用它,例如[v for v in accumulate(rand(100))];但是,如果只使用列表推导式,则无法访问到目前为止生成的先前元素。 - Martijn Pieters
确实,这是一种优雅的方法,但我不确定是否有一种简洁的方式在列表推导中累加总和。同意这可能不是最佳实践,但在命令行上工作时使用紧凑形式很方便。 - Pierz

4

既然您已经在使用 numpy,因此可以使用 cumsum

>>> from numpy.random import rand
>>> x = rand(10)
>>> x
array([ 0.33006219,  0.75246128,  0.62998073,  0.87749341,  0.96969786,
        0.02256228,  0.08539008,  0.83715312,  0.86611906,  0.97415447])
>>> x.cumsum()
array([ 0.33006219,  1.08252347,  1.7125042 ,  2.58999762,  3.55969548,
        3.58225775,  3.66764783,  4.50480095,  5.37092001,  6.34507448])

1

关于以上答案的更新,我找到了一种更简单、更好的方法。以前为什么没想到呢?使用总是用括号()括起来的海豹运算符:=的项有一个返回值,不像普通赋值。因此,在命令行中test=0会静默执行,但(test:=0)会在屏幕上打印出0。所以在这方面,它就像一个函数,有一个返回值。因此,它可以放在列表推导的内容部分,而不是在可丢弃的“if”中使用or True。
所以代码变成了:

import numpy as np

sum=0
array=[(sum:=sum+i) for i in np.random.rand(100)]

1
请注意,您可以编辑旧答案以添加此部分。这将防止未来用户需要查找先前的答案或根本找不到此答案。 - GregoirePelegrin

0

好的,你说你不想用 numpy 但是这是我的解决方案。 我认为你只是在对累积求和,所以使用 cumsum() 函数。

import numpy as np
result = np.cumsum(some_array)

一个随机的例子
result = np.cumsum(np.random.uniform(size=100))

0

这里有一个滥用Python3.8中的:=“海象操作符”的概念。它在更大的表达式中赋值变量。我的印象是为了让用户免于在“if”的测试部分计算某些内容,然后必须在可执行部分再次计算。但是,它并不局限于“if”,所以您可以在定义后随时使用该变量。因此,此方法在列表解析中使用始终为True的if作为重新赋值的位置。不幸的是,“+:=”不是运算符,因此您必须执行手动加法赋值而不是“+=”。

import numpy as np

sum=0
array=[sum for i in np.random.rand(100) if (sum:=sum+i) or True]

1
你不需要使用if语句。例如,s = 0; seq = [s:=s+i for i in range(9)]可以生成一个累加和的序列。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接