2013-04-08 17 views
41
time_interval = [4, 6, 12] 

Voglio riassumere i numeri come [4, 4+6, 4+6+12] per ottenere l'elenco t = [4, 10, 22].Come trovare la somma cumulativa di numeri in una lista?

ho provato la seguente:

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 
+11

Nota a margine: non chiamare un elenco 'lista'. Questo è il nome della funzione built-in utilizzata per convertire altre cose in elenchi e non si desidera nasconderlo. – abarnert

+0

Vedere anche http://stackoverflow.com/q/9258602 – hpaulj

risposta

-8

Rispondendo alla domanda iniziale chiedendo come "per riassumere i numeri in un elenco": Controlla la funzione di somma built-in(), probabilmente fa quello che si volere.

+0

Non del tutto; ha bisogno di trasformare una sequenza in una serie. – abarnert

+0

Forse. My Crystal Ball (tm) non è abbastanza buono per dirlo con certezza. ;) –

+7

Bene, fornisce l'output atteso, '[4, 10, 22]', quindi non hai davvero bisogno di una sfera di cristallo per sapere che '22' non è la risposta giusta. – abarnert

56

In Python 2 è possibile definire la propria funzione di generatore in questo modo:

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] 

E in Python 3.2 + è possibile utilizzare itertools.accumulate():

In [1]: lis = [4,6,12] 

In [2]: from itertools import accumulate 

In [3]: list(accumulate(lis)) 
Out[3]: [4, 10, 22] 
1

In primo luogo, si vuole un elenco aggiornato dei sottosuccessioni :

subseqs = (seq[:i] for i in range(1, len(seq)+1)) 

Quindi basta chiamare sum su eac h subsequence:

sums = [sum(subseq) for subseq in subseqs] 

(Questo non è il modo più efficace per farlo, perché si sta aggiungendo tutti i prefissi più volte. Ma questo probabilmente non ha importanza per la maggior parte dei casi di utilizzo.)

Se stai usando Python 3.2 o più recente, puoi usare itertools.accumulate in farlo per voi:

sums = itertools.accumulate(seq) 

e se si sta utilizzando 3.1 o versioni precedenti, si può semplicemente copiare il "equivale a" fonte direttamente fuori la documentazione (ad eccezione di cambiare next(it)-it.next() per 2,5 e precedenti).

+7

Esegue in tempo quadratico (forse ciò non ha importanza per l'OP, ma vale la pena menzionarlo). –

+0

Per prima cosa, quando N = 3, a chi importa del tempo quadratico? E non penso sia complicato. Sono due passaggi molto semplici, ognuno dei quali trasforma un iteratore in un altro, traducendo direttamente la descrizione in lingua inglese. (Il fatto che stia usando un modo non comune di definire serie, dove il prefisso di lunghezza 0 non è contato, lo rende un po 'più complicato ... ma questo è inerente al problema, e ho pensato che fosse meglio metterlo nella 'range' piuttosto che hackerarlo attorno facendo' [1:] 'alla fine, o ignorarlo.) – abarnert

+0

Presumibilmente il problema reale dell'OP non è quello di ottenere le somme parziali di' [4,6,12] ' poiché, come ha scritto nella domanda, sa già di cosa si tratta! –

2

Prova questo: (? Liste più grandi)

result = [] 
acc = 0 
for i in time_interval: 
    acc += i 
    result.append(acc) 
2
values = [4, 6, 12] 
total = 0 
sums = [] 

for v in values: 
    total = total + v 
    sums.append(total) 

print 'Values: ', values 
print 'Sums: ', sums 

L'esecuzione di questo codice dà

Values: [4, 6, 12] 
Sums: [4, 10, 22] 
1
lst = [4,6,12] 

[sum(lst[:i+1]) for i in xrange(len(lst))] 

Se siete alla ricerca di una soluzione più efficiente un generatore potrebbe essere un buona chiamata (o semplicemente usare numpy se ti interessa davvero il perf).

def gen(lst): 
    acu = 0 
    for num in lst: 
     yield num + acu 
     acu += num 

print list(gen([4, 6, 12])) 
0
In [42]: a = [4, 6, 12] 

In [43]: [sum(a[:i+1]) for i in xrange(len(a))] 
Out[43]: [4, 10, 22] 

Questo è slighlty più veloce rispetto al metodo di generatore di cui sopra da @Ashwini per le piccole liste

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 

Per le liste più grandi, il generatore è la strada da percorrere per certo. . .

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 
+1

Hai tempistiche per solo 3 voci, prova per 10^4 articoli. –

+1

Vero, per gli elenchi più grandi il generatore è molto più veloce! – reptilicus

+0

Ho modificato la mia risposta per dimostrarlo. – reptilicus

62

Se si sta facendo molto lavoro numerica con gli array come questo, io suggerirei numpy, che viene fornito con una funzione di somma cumulativa cumsum:

import numpy as np 

a = [4,6,12] 

np.cumsum(a) 
#array([4, 10, 22]) 

Numpy è spesso più veloce puro Python per questo genere di cose, vedere in confronto al @Ashwini's 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 

Ma naturalmente se è l'unico posto che verrà utilizzato NumPy, potrebbe non essere w ort avere dipendenza da esso.

+1

Questo dovrebbe avere un caso 'np.cumsun' che inizia con un elenco, per tenere conto del tempo di conversione. – hpaulj

+2

Buon punto @hpaulj, per quelli che iniziano (o mirano a) un 'elenco' non mi raccomando' numpy'. – askewchan

+0

Non credo che Numpy sia più veloce http://stackoverflow.com/questions/15889131/how-to-find-the-cumulative-sum-of-numbers-in-a-list/39534850#39534850 –

0

Un po 'hacky, ma sembra funzionare:

def cumulative_sum(l): 
    y = [0] 
    def inc(n): 
    y[0] += n 
    return y[0] 
    return [inc(x) for x in l] 

pensavo che la funzione interna sarebbe in grado di modificare la y dichiarato nel scope lessicale esterno, ma che non ha funzionato, così abbiamo giochiamo alcuni brutti hack con modifica della struttura. Probabilmente è più elegante usare un generatore.

0

Senza dover utilizzare Numpy, è possibile eseguire il ciclo direttamente sull'array e accumulare la somma lungo la strada. Per esempio:

a=range(10) 
i=1 
while((i>0) & (i<10)): 
    a[i]=a[i-1]+a[i] 
    i=i+1 
print a 

risultati in:

[0, 1, 3, 6, 10, 15, 21, 28, 36, 45] 
10

Ecco:

a = [4, 6, 12] 
reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:] 

uscita Will (come previsto):

[4, 10, 22] 
+0

Risposta eccellente ed efficiente pure! –

+6

* Non * efficiente. La spesa totale per eseguire 'c + [c [-1] + x]' più e più volte si somma a un quadratico di runtime totale nella lunghezza di input. – user2357112

+0

riduzione è buono per una somma cumulativa una tantum, ma se stai facendo molte chiamate alla tua funzione cumsum un generatore sarà utile per "pre-elaborare" i tuoi valori cumulativi e accedervi in ​​O (1) per ogni chiamata successiva . –

0
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 
-1

T il suo sarebbe Haskell-style:

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]) 
5

ho fatto una panchina-mark dei primi due risposte con Python 3.4 e ho trovato itertools.accumulate è più veloce di numpy.cumsum in molte circostanze, spesso molto più veloce. Tuttavia, come puoi vedere dai commenti, questo potrebbe non essere sempre il caso, ed è difficile esplorare esaustivamente tutte le opzioni. (Sentiti libero di aggiungere un commento o modificare questo post se hai ulteriori risultati di riferimento di interesse.)

Alcuni tempi ...

Per brevi liste accumulate è di circa 4 volte più veloce:

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 

Per gli elenchi più lunghi accumulate è di circa 3 volte più veloce:

l = [1, 2, 3, 4, 5]*1000 
timeit(lambda: sum1(l), number=100000) 
# 19.174508565105498 
timeit(lambda: sum2(l), number=100000) 
# 61.871223849244416 

Se il numpyarray non è gettato a list, accumulate è ancora circa 2 volte più veloce:

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 

Se si mettono le importazioni al di fuori delle due funzioni ed ancora restituire un numpyarray, accumulate è ancora quasi 2 volte più veloce:

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 
+4

Non ti aspetteresti che un aereo sia più veloce del treno per viaggiare attraverso la città, specialmente per l'acquisto di biglietti e lo screening di sicurezza. Allo stesso modo non si userebbe numpy per elaborare un 'elenco' di cinque elementi, specialmente se non si è disposti ad accettare un' array' in cambio. Se la lista in questione è davvero così breve, allora il loro tempo di esecuzione sarebbe _inconseguente _--- le dipendenze e sicuramente la leggibilità sarebbe dominante. Ma un ampio uso di una lista di tipi di dati numerici uniformi di lunghezza significativa sarebbe sciocco; per questo, un 'array' numerico dovrebbe essere appropriato, e in genere più veloce. – askewchan

+0

@askewchan beh, non lo trovo solo per le liste brevi e la domanda dell'OP chiede un elenco come output piuttosto che un array numpy. Forse è possibile modificare la risposta per essere più chiara quando ogni utilizzo è appropriato :) –

+0

@askewchan In realtà ho modificato la mia risposta con un confronto molto più dettagliato. In nessuna circostanza, trovo 'numpy' essere più veloce, a meno che non abbia trascurato qualcosa? –

2

Se vuoi un modo divinatorio senza NumPy lavorare in 2.7 questo sarebbe il mio modo di fare

l = [1,2,3,4] 
_d={-1:0} 
cumsum=[_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)] 

ora proviamo e testarla contro tutte le altre implementazioni

import timeit 
L=range(10000) 

def sum1(l): 
    cumsum=[] 
    total = 0 
    for v in l: 
     total += v 
     cumsum.append(total) 
    return cumsum 


def sum2(l): 
    import numpy as np 
    return list(np.cumsum(l)) 

def sum3(l): 
    return [sum(l[:i+1]) for i in xrange(len(l))] 

def sum4(l): 
    return reduce(lambda c, x: c + [c[-1] + x], l, [0])[1:] 

def this_implementation(l): 
    _d={-1:0} 
    return [_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)] 


# sanity check 
sum1(L)==sum2(L)==sum3(L)==sum4(L)==this_implementation(L) 
>>> True  

# PERFORMANCE TEST 
timeit.timeit('sum1(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. 
>>> 0.001018061637878418 

timeit.timeit('sum2(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. 
>>> 0.000829620361328125 

timeit.timeit('sum3(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. 
>>> 0.4606760001182556 

timeit.timeit('sum4(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. 
>>> 0.18932826995849608 

timeit.timeit('this_implementation(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. 
>>> 0.002348129749298096