Elegant pythonic cumsum

前端 未结 10 1104
-上瘾入骨i
-上瘾入骨i 2020-12-16 11:54

What would be an elegant and pythonic way to implement cumsum?
Alternatively - if there\'a already a built-in way to do it, that would be even better of course...

相关标签:
10条回答
  • 2020-12-16 12:25

    in place:

    a=[1,2,3,4,5]
    def cumsum(a):
        for i in range(1,len(a)):
            a[i]+=a[i-1]
    
    cumsum(a)
    print a
    "[1, 3, 6, 10, 15]"
    
    0 讨论(0)
  • 2020-12-16 12:27

    I have updated @GrantJ 's answer and have timed everything with Python 3 in Jupyter. I have added in the following simple accumulate example:

    def cumsum_acc(iterable):
        return accumulate(iterable)
    

    The timings show that this approach is the fastest:

    reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), values_ten, ([], 0))[0]
    Average: 4.18553415873987e-06
    reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), values_mil, ([], 0))[0]
    Average: 0.4559302114011018
    reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), values_ten, [0])[1:]
    Average: 3.3726942356950078e-06
    reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), values_mil, [0])[1:]
    Average: 0.4217967894903154
    cumsum_rking(values_ten)
    Average: 2.2734952410773416e-06
    cumsum_rking(values_mil)
    Average: 0.24106813411868303
    list(cumsum_larsmans(values_ten))
    Average: 1.5819200433296032e-06
    list(cumsum_larsmans(values_mil))
    Average: 0.17061943569953542
    list(cumsum_acc(values_ten))
    Average: 9.456979988264607e-07
    list(cumsum_acc(values_mil))
    Average: 0.11057746014014924
    

    The code behind it (by GrantJ, modified for Python 3):

    from timeit import timeit
    from itertools import accumulate
    from functools import reduce
    
    def bmark(prog, setup, number):
        duration = timeit(prog, setup=setup, number=number)
        print(prog)
        print('Average:', duration / number)
    
    values_ten = list(range(10))
    values_mil = list(range(1000000))
    
    from operator import iadd
    
    bmark('reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), \
    values_ten, ([], 0))[0]',
          setup='from __main__ import iadd, reduce, values_ten', number=1000000)
    bmark('reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), \
    values_mil, ([], 0))[0]',
          setup='from __main__ import iadd, reduce, values_mil', number=10)
    
    bmark('reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), \
    values_ten, [0])[1:]',
          setup='from __main__ import iadd, reduce, values_ten', number=1000000)
    bmark('reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), \
    values_mil, [0])[1:]',
          setup='from __main__ import iadd, reduce, values_mil', number=10)
    
    def cumsum_rking(iterable):
        values = list(iterable)
        for pos in range(1, len(values)):
            values[pos] += values[pos - 1]
        return values
    
    bmark('cumsum_rking(values_ten)',
          setup='from __main__ import cumsum_rking, values_ten', number=1000000)
    bmark('cumsum_rking(values_mil)',
          setup='from __main__ import cumsum_rking, values_mil', number=10)
    
    def cumsum_larsmans(iterable):
        total = 0
        for value in iterable:
            total += value
            yield total
    
    bmark('list(cumsum_larsmans(values_ten))',
          setup='from __main__ import cumsum_larsmans, values_ten', number=1000000)
    bmark('list(cumsum_larsmans(values_mil))',
          setup='from __main__ import cumsum_larsmans, values_mil', number=10)
    
    def cumsum_acc(iterable):
        return accumulate(iterable)
    
    bmark('list(cumsum_acc(values_ten))',
          setup='from __main__ import cumsum_acc, accumulate, values_ten', number=1000000)
    bmark('list(cumsum_acc(values_mil))',
          setup='from __main__ import cumsum_acc, accumulate, values_mil', number=10)
    
    0 讨论(0)
  • 2020-12-16 12:28

    Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), we can use and increment a variable within a list comprehension:

    total = 0
    [total := total + x for x in [1, 2, 3 ,4, 5]]
    # [1, 3, 6, 10, 15]
    

    This:

    • Initializes a variable total to 0 which symbolizes the cumulative sum
    • For each item, this both:
      • increments total with the current looped item (total := total + x) via an assignment expression
      • and at the same time, maps x to the new value of total
    0 讨论(0)
  • 2020-12-16 12:29

    for loops are pythonic

    def cumsum(vec):
        r = [vec[0]]
        for val in vec[1:]:
            r.append(r[-1] + val)
        return r
    
    0 讨论(0)
  • 2020-12-16 12:33
    def cumsum(a):
         return map(lambda x: sum( a[0:x+1] ), range( 0, len(a) ))
    
    cumsum([1,2,3])
    
    > [1, 3, 6]
    
    0 讨论(0)
  • 2020-12-16 12:34
    a=[1,2,3,4,5]
    
    def cumsum(a):
        a=iter(a)
        cc=[next(a)]
        for i in a:
            cc.append(cc[-1]+i)
        return cc
    
    print cumsum(a)
    "[1, 3, 6, 10, 15]"
    
    0 讨论(0)
提交回复
热议问题