如何查找列表中的累计数字总和?
time_interval = [4, 6, 12]
我想总结一下[4, 4+6, 4+6+12]
这样的数字来得到列表t = [4, 10, 22]
。
我尝试了以下内容:
for i in time_interval: t1 = time_interval[0] t2 = time_interval[1] + t1 t3 = time_interval[2] + t2 print(t1, t2, t3) 4 10 22 4 10 22 4 10 22
如果你正在用这样的数组做很多数值工作,我会建议numpy
,它带有一个累积求和函数cumsum
:
import numpy as np a = [4,6,12] np.cumsum(a) #array([4, 10, 22])
对于这种事情,Numpy通常比纯Python更快,相比之下, @ Ashwini的accumu
:
In [136]: timeit list(accumu(range(1000))) 10000 loops, best of 3: 161 us per loop In [137]: timeit list(accumu(xrange(1000))) 10000 loops, best of 3: 147 us per loop In [138]: timeit np.cumsum(np.arange(1000)) 100000 loops, best of 3: 10.1 us per loop
但是,当然,如果它是唯一使用numpy的地方,可能不值得依赖它。
在Python 2中,您可以像这样定义自己的生成器函数:
def accumu(lis): total = 0 for x in lis: total += x yield total In [4]: list(accumu([4,6,12])) Out[4]: [4, 10, 22]
在Python 3.2+中,你可以使用itertools.accumulate()
:
In [1]: lis = [4,6,12] In [2]: from itertools import accumulate In [3]: list(accumulate(lis)) Out[3]: [4, 10, 22]
看吧:
a = [4, 6, 12] reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]
将输出(如预期):
[4, 10, 22]
我用Python 3.4对前两个答案做了一个基准numpy.cumsum
在很多情况下我发现itertools.accumulate
比numpy.cumsum
要快,通常要快得多。 然而,正如您从评论中看到的那样,情况可能并非总是如此,并且很难详尽地探索所有选项。 (如果您有进一步的基准测试结果,请随意添加评论或编辑此文章。)
一些时间…
对于短名单accumulate
约4倍的速度:
from timeit import timeit def sum1(l): from itertools import accumulate return list(accumulate(l)) def sum2(l): from numpy import cumsum return list(cumsum(l)) l = [1, 2, 3, 4, 5] timeit(lambda: sum1(l), number=100000) # 0.4243644131347537 timeit(lambda: sum2(l), number=100000) # 1.7077815784141421
对于更长的列表, accumulate
速度大约快3倍:
l = [1, 2, 3, 4, 5]*1000 timeit(lambda: sum1(l), number=100000) # 19.174508565105498 timeit(lambda: sum2(l), number=100000) # 61.871223849244416
如果numpy
array
没有强制转换为list
,那么accumulate
速度仍然快了2倍:
from timeit import timeit def sum1(l): from itertools import accumulate return list(accumulate(l)) def sum2(l): from numpy import cumsum return cumsum(l) l = [1, 2, 3, 4, 5]*1000 print(timeit(lambda: sum1(l), number=100000)) # 19.18597290944308 print(timeit(lambda: sum2(l), number=100000)) # 37.759664884768426
如果你把这两个函数的输入放在外面,并且仍然返回一个numpy
array
,那么accumulate
仍然快了2倍:
from timeit import timeit from itertools import accumulate from numpy import cumsum def sum1(l): return list(accumulate(l)) def sum2(l): return cumsum(l) l = [1, 2, 3, 4, 5]*1000 timeit(lambda: sum1(l), number=100000) # 19.042188624851406 timeit(lambda: sum2(l), number=100000) # 35.17324400227517
values = [4, 6, 12] total = 0 sums = [] for v in values: total = total + v sums.append(total) print 'Values: ', values print 'Sums: ', sums
运行这个代码给出
Values: [4, 6, 12] Sums: [4, 10, 22]
首先,你需要一个子序列的运行列表:
subseqs = (seq[:i] for i in range(1, len(seq)+1))
那么你只需要对每个子序列sum
:
sums = [sum(subseq) for subseq in subseqs]
(这不是最有效的方法,因为你要重复添加所有的前缀,但是对于大多数用例来说这可能并不重要,如果你不必考虑运行总数。)
如果您使用的是Python 3.2或更新的版本,则可以使用itertools.accumulate
为您完成:
sums = itertools.accumulate(seq)
如果您使用的是3.1或更早的版本,您可以直接从文档中复制“等效”源代码(除了将其更改为2.5以及更早版本之后,将next(it)
更改为it.next()
)。
尝试这个:
result = [] acc = 0 for i in time_interval: acc += i result.append(acc)
lst = [4,6,12] [sum(lst[:i+1]) for i in xrange(len(lst))]
如果你正在寻找一个更有效的解决方案(更大的列表?)一个生成器可以是一个很好的电话(或者如果你真的关心性能只是使用numpy
)。
def gen(lst): acu = 0 for num in lst: yield num + acu acu += num print list(gen([4, 6, 12]))
In [42]: a = [4, 6, 12] In [43]: [sum(a[:i+1]) for i in xrange(len(a))] Out[43]: [4, 10, 22]
这比上面的@Ashwini的小生成器生成器方法要小得多
In [48]: %timeit list(accumu([4,6,12])) 100000 loops, best of 3: 2.63 us per loop In [49]: %timeit [sum(a[:i+1]) for i in xrange(len(a))] 100000 loops, best of 3: 2.46 us per loop
对于更大的列表,发电机是确定的方式。 。 。
In [50]: a = range(1000) In [51]: %timeit [sum(a[:i+1]) for i in xrange(len(a))] 100 loops, best of 3: 6.04 ms per loop In [52]: %timeit list(accumu(a)) 10000 loops, best of 3: 162 us per loop
有点哈克,但似乎工作:
def cumulative_sum(l): y = [0] def inc(n): y[0] += n return y[0] return [inc(x) for x in l]
我确实认为内部函数可以修改在外部词法范围内声明的y
,但是这并不起作用,所以我们用结构修改来玩一些讨厌的黑客。 使用发生器可能更优雅。
不必使用Numpy,你可以直接在数组上循环,并沿途累积总和。 例如:
a=range(10) i=1 while((i>0) & (i<10)): a[i]=a[i-1]+a[i] i=i+1 print a
结果是:
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
def cummul_sum(list_arguement): cumm_sum_lst = [] cumm_val = 0 for eachitem in list_arguement: cumm_val += eachitem cumm_sum_lst.append(cumm_val) return cumm_sum_lst
这将是Haskell风格:
def wrand(vtlg): def helpf(lalt,lneu): if not lalt==[]: return helpf(lalt[1::],[lalt[0]+lneu[0]]+lneu) else: lneu.reverse() return lneu[1:] return helpf(vtlg,[0])
看看内置的sum()函数,它可能是你想要的。