如何在列表中找到累计的数字总和?

use*_*323 72 python sum list accumulate

time_interval = [4, 6, 12]
Run Code Online (Sandbox Code Playgroud)

我想总结数字[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
Run Code Online (Sandbox Code Playgroud)

ask*_*han 98

如果你正在使用这样的数组做很多数值工作,我建议numpy,它带有累积和函数cumsum:

import numpy as np

a = [4,6,12]

np.cumsum(a)
#array([4, 10, 22])
Run Code Online (Sandbox Code Playgroud)

对于这种事情,Numpy通常比纯python更快,与@ Ashwiniaccumu相比:

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
Run Code Online (Sandbox Code Playgroud)

但是当然如果它是唯一一个你会使用numpy的地方,它可能不值得依赖它.

  • 好点@hpaulj,对于那些从(或瞄准)'list'开始的人,我不推荐`numpy`. (3认同)
  • 正如我上面提到的,同意。避免像你和@hpaulj这样的反应是为什么我试图在答案的第一行和最后一行中限制其范围的原因:-/ (3认同)
  • 考虑到转换时间,应该有一个以列表开头的np.cumsun案例。 (2认同)

Ash*_*ary 81

在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]
Run Code Online (Sandbox Code Playgroud)

在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]
Run Code Online (Sandbox Code Playgroud)

  • [PEP 572-赋值表达式](https://www.python.org/dev/peps/pep-0572/)(预期用于Python 3.8)显示了一个有趣的替代选项,总计= 0;partial_sums = [total:= total + v中的v值]`。我仍然希望“积累”会更快。 (3认同)
  • @StevenRumbalski Man,我个人认为这是有史以来最糟糕的PEP。[不够好...](https://mail.python.org/pipermail/python-committers/2018-July/005664.html) (2认同)

won*_*ice 18

看吧:

a = [4, 6, 12]
reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]
Run Code Online (Sandbox Code Playgroud)

将输出(如预期):

[4, 10, 22]
Run Code Online (Sandbox Code Playgroud)

  • *不高效.执行"c + [c [-1] + x]`的总费用总计为输入长度的总运行时间二次方. (11认同)

小智 16

试试这个 itertools.accumulate()功能。

import itertools  

list(itertools.accumulate([1,2,3,4,5]))
# [1, 3, 6, 10, 15]
Run Code Online (Sandbox Code Playgroud)

  • 您不需要传递`operator.add`,因为无论如何默认操作都是加法。 (9认同)

Chr*_*nds 13

我用Python 3.4做了前两个答案的基准测试,我发现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
Run Code Online (Sandbox Code Playgroud)

对于较长的列表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
Run Code Online (Sandbox Code Playgroud)

如果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
Run Code Online (Sandbox Code Playgroud)

如果你把导入放在两个函数之外但仍然返回一个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
Run Code Online (Sandbox Code Playgroud)

  • 你不会指望飞机比火车穿越城镇更快,特别是包括购票和安全检查.同样地,你不会使用numpy来处理五个项目的`list`,特别是如果你不愿意接受一个`array`作为回报.如果有问题的列表真的那么短,那么它们的运行时间将是_inconsequential _---依赖性和可读性肯定会占主导地位.但广泛使用长度相当的统一数值数据类型的"列表"将是愚蠢的; 为此,一个numpy`array`_would_是合适的,通常更快. (10认同)
  • 哦,我的确是的:)我不会说你忽略了某些东西,但是如果不考虑你的输入和输出,这种比较很难孤立.你的`sum2`函数中的大部分时间都可能是将`l`转换为数组.尝试分别计时`a = np.array(l)`和`np.cumsum(a)`.然后尝试`a = np.tile(np.arange(1,6),1000)`vs`l = [1,2,3,4,5]*1000`.在一个执行其他数值过程的程序中(比如首先创建或加载`l`),你的工作数据可能已经在一个数组中,并且创建将是一个不变的成本. (2认同)
  • @askewchan 我和你有同样的想法,因此我对 a = np.array(l) 进行了计时。对于没有转换为列表且使用 numpy 数组作为输入的 sum2,在长列表/数组的情况下,sum2 的速度快了 5 倍,感谢我计算机中的 sum1。 (2认同)

Ste*_*ski 12

PEP 572(Python 3.8 中的新功能)中的赋值表达式提供了另一种解决此问题的方法:

time_interval = [4, 6, 12]

total_time = 0
cum_time = [total_time := total_time + t for t in time_interval]
Run Code Online (Sandbox Code Playgroud)


Eug*_*ash 8

您可以使用简单的for循环在线性时间内计算累积总和列表:

def csum(lst):
    s = lst.copy()
    for i in range(1, len(s)):
        s[i] += s[i-1]
    return s

time_interval = [4, 6, 12]
print(csum(time_interval))  # [4, 10, 22]
Run Code Online (Sandbox Code Playgroud)

标准库itertools.accumulate可能是一个更快的替代方案(因为它是用 C 实现的):

from itertools import accumulate
time_interval = [4, 6, 12]
print(list(accumulate(time_interval)))  # [4, 10, 22]
Run Code Online (Sandbox Code Playgroud)


Via*_*v Z 7

python 3.8开始,可以使用赋值表达式,所以这样的事情变得更容易实现

nums = list(range(1, 10))
print(f'array: {nums}')

v = 0
cumsum = [v := v + n for n in nums]
print(f'cumsum: {cumsum}')
Run Code Online (Sandbox Code Playgroud)

产生

array: [1, 2, 3, 4, 5, 6, 7, 8, 9]
cumsum: [1, 3, 6, 10, 15, 21, 28, 36, 45]
Run Code Online (Sandbox Code Playgroud)

可以应用相同的技术来查找乘积、平均值等。

p = 1
cumprod = [p := p * n for n in nums]
print(f'cumprod: {cumprod}')

s = 0
c = 0
cumavg = [(s := s + n) / (c := c + 1) for n in nums]
print(f'cumavg: {cumavg}')
Run Code Online (Sandbox Code Playgroud)

结果是

cumprod: [1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
cumavg: [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
Run Code Online (Sandbox Code Playgroud)