time_interval = [4, 6, 12]
Je veux résumer les nombres comme [4, 4+6, 4+6+12]
pour obtenir la liste t = [4, 10, 22]
.
J'ai essayé ce qui suit:
t1 = time_interval[0]
t2 = time_interval[1] + t1
t3 = time_interval[2] + t2
print(t1, t2, t3) # -> 4 10 22
python
list
sum
accumulate
user2259323
la source
la source
Réponses:
Si vous faites beaucoup de travail numérique avec des tableaux comme celui-ci, je suggère
numpy
, qui est livré avec une fonction de somme cumulativecumsum
:import numpy as np a = [4,6,12] np.cumsum(a) #array([4, 10, 22])
Numpy est souvent plus rapide que le python pur pour ce genre de chose, voir en comparaison avec @ 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
Mais bien sûr, si c'est le seul endroit où vous utiliserez numpy, cela ne vaut peut-être pas la peine d'en dépendre.
la source
np.cumsun
cas qui commence par une liste, pour prendre en compte le temps de conversion.list
je ne recommanderais pasnumpy
.timeit
, "s'il-n
n'est pas donné, un nombre approprié de boucles est calculé en essayant des puissances successives de 10 jusqu'à ce que le temps total soit d'au moins 0,2 seconde." Si vous vous attendez à ce que cela fasse une différence, vous pouvez fournir-n 1000
pour les rendre tous équivalents.Dans Python 2, vous pouvez définir votre propre fonction de générateur comme ceci:
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]
Et dans Python 3.2+, vous pouvez utiliser
itertools.accumulate()
:In [1]: lis = [4,6,12] In [2]: from itertools import accumulate In [3]: list(accumulate(lis)) Out[3]: [4, 10, 22]
la source
total = 0; partial_sums = [total := total + v for v in values]
. Je m'attendrais toujoursaccumulate
à être plus rapide.Voir:
a = [4, 6, 12] reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]
Sortira (comme prévu):
[4, 10, 22]
la source
c + [c[-1] + x]
répétée s'ajoute à un quadratique d'exécution total dans la longueur d'entrée.J'ai fait un benchmark des deux premières réponses avec Python 3.4 et j'ai trouvé que
itertools.accumulate
c'est plus rapide quenumpy.cumsum
dans de nombreuses circonstances, souvent beaucoup plus rapide. Cependant, comme vous pouvez le voir dans les commentaires, ce n'est peut-être pas toujours le cas et il est difficile d'explorer de manière exhaustive toutes les options. (N'hésitez pas à ajouter un commentaire ou à modifier cet article si vous avez d'autres résultats de référence intéressants.)Quelques horaires ...
Pour les listes courtes,
accumulate
c'est environ 4 fois plus rapide: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
Pour des listes plus longues,
accumulate
c'est environ 3 fois plus rapide:l = [1, 2, 3, 4, 5]*1000 timeit(lambda: sum1(l), number=100000) # 19.174508565105498 timeit(lambda: sum2(l), number=100000) # 61.871223849244416
Si le
numpy
array
n'est pas casté verslist
,accumulate
est toujours environ 2 fois plus rapide: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
Si vous mettez les importations en dehors des deux fonctions et retournez toujours a
numpy
array
,accumulate
c'est toujours presque 2 fois plus rapide: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
la source
list
des cinq éléments, surtout si vous ne souhaitez pas accepter unarray
en retour. Si la liste en question est vraiment si courte, alors leur durée d'exécution serait sans conséquence - les dépendances et la lisibilité domineraient sûrement. Mais une large utilisation d'unlist
type de données numériques uniformes de longueur significative serait ridicule; pour cela, un numpyarray
serait approprié, et généralement plus rapide.numpy
être plus rapide, sauf si j'ai oublié quelque chose?sum2
fonction consiste probablement à convertirl
en tableau. Essayez de chronométrera = np.array(l)
etnp.cumsum(a)
séparément. Ensuite , essayeza = np.tile(np.arange(1, 6), 1000)
vsl = [1,2,3,4,5]*1000
. Dans un programme effectuant d'autres processus numériques (comme la création ou le chargementl
en premier lieu), vos données de travail seraient probablement déjà dans un tableau, et la création serait un coût constant.Essayez ceci: la fonction d'accumulation, avec l'opérateur add, effectue l'addition en cours.
import itertools import operator result = itertools.accumulate([1,2,3,4,5], operator.add) list(result)
la source
operator.add
car l'opération par défaut est l'addition de toute façon.Les expressions d'affectation de PEP 572 (nouveau dans Python 3.8) offrent encore un autre moyen de résoudre ce problème:
time_interval = [4, 6, 12] total_time = 0 cum_time = [total_time := total_time + t for t in time_interval]
la source
Vous pouvez calculer la liste de somme cumulée en temps linéaire avec une simple
for
boucle: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]
La bibliothèque standard
itertools.accumulate
peut être une alternative plus rapide (puisqu'elle est implémentée en C):from itertools import accumulate time_interval = [4, 6, 12] print(list(accumulate(time_interval))) # [4, 10, 22]
la source
values = [4, 6, 12] total = 0 sums = [] for v in values: total = total + v sums.append(total) print 'Values: ', values print 'Sums: ', sums
L'exécution de ce code donne
Values: [4, 6, 12] Sums: [4, 10, 22]
la source
En Python3, pour trouver la somme cumulée d'une liste où le
i
ème élément est la somme des i + 1 premiers éléments de la liste d'origine, vous pouvez faire:a = [4 , 6 , 12] b = [] for i in range(0,len(a)): b.append(sum(a[:i+1])) print(b)
OU vous pouvez utiliser la compréhension de liste:
b = [sum(a[:x+1]) for x in range(0,len(a))]
Production
[4,10,22]
la source
Si vous voulez une manière pythonique sans travailler numpy en 2.7, ce serait ma façon de le faire
l = [1,2,3,4] _d={-1:0} cumsum=[_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)]
maintenant essayons-le et testons-le contre toutes les autres implémentations
import timeit, sys L=list(range(10000)) if sys.version_info >= (3, 0): reduce = functools.reduce xrange = range 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
la source
Il peut y avoir plusieurs réponses à cela en fonction de la longueur de la liste et de la performance. Une manière très simple à laquelle je peux penser sans penser à la performance est la suivante:
a = [1, 2, 3, 4] a = [sum(a[0:x:1]) for x in range(len(a)+1)][1:] print(a)
[1, 3, 6, 10]
C'est en utilisant la compréhension de liste et cela peut fonctionner assez bien, c'est juste qu'ici j'ajoute plusieurs fois sur le sous-tableau, vous pourriez éventuellement improviser là-dessus et le rendre simple!
Bravo à votre effort!
la source
Tout d'abord, vous voulez une liste courante de sous-séquences:
subseqs = (seq[:i] for i in range(1, len(seq)+1))
Ensuite, vous appelez simplement
sum
chaque sous-séquence:sums = [sum(subseq) for subseq in subseqs]
(Ce n'est pas le moyen le plus efficace de le faire, car vous ajoutez tous les préfixes à plusieurs reprises. Mais cela n'aura probablement pas d'importance dans la plupart des cas d'utilisation, et c'est plus facile à comprendre si vous n'avez pas à penser à les totaux cumulés.)
Si vous utilisez Python 3.2 ou plus récent, vous pouvez le
itertools.accumulate
faire pour vous:Et si vous utilisez la version 3.1 ou antérieure, vous pouvez simplement copier la source «équivalent à» directement à partir de la documentation (sauf pour passer
next(it)
à la versionit.next()
2.5 et antérieure).la source
range
que de le contourner en le faisant[1:]
à la fin, ou de l'ignorer.)[4,6,12]
puisque, comme il l'a écrit dans la question, il sait déjà ce que c'est!Essaye ça:
result = [] acc = 0 for i in time_interval: acc += i result.append(acc)
la source
In [42]: a = [4, 6, 12] In [43]: [sum(a[:i+1]) for i in xrange(len(a))] Out[43]: [4, 10, 22]
C'est légèrement plus rapide que la méthode du générateur ci-dessus par @Ashwini pour les petites listes
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
Pour les listes plus volumineuses, le générateur est la solution. . .
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
la source
Un peu hacky, mais semble fonctionner:
def cumulative_sum(l): y = [0] def inc(n): y[0] += n return y[0] return [inc(x) for x in l]
Je pensais que la fonction interne serait capable de modifier le
y
déclaré dans la portée lexicale externe, mais cela n'a pas fonctionné, nous avons donc joué à de vilains hacks avec une modification de structure à la place. Il est probablement plus élégant d'utiliser un générateur.la source
Sans avoir à utiliser Numpy, vous pouvez effectuer une boucle directement sur le tableau et accumuler la somme en cours de route. Par exemple:
a=range(10) i=1 while((i>0) & (i<10)): a[i]=a[i-1]+a[i] i=i+1 print a
Résulte en:
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
la source
Un pur python oneliner pour la somme cumulée:
cumsum = lambda X: X[:1] + cumsum([X[0]+X[1]] + X[2:]) if X[1:] else X
Il s'agit d'une version récursive inspirée des sommes cumulatives récursives . Quelques explications:
X[:1]
est une liste contenant l'élément précédent et est presque le même que[X[0]]
(ce qui se plaindrait pour les listes vides).cumsum
appel récursif du second terme traite l'élément courant[1]
et la liste restante dont la longueur sera réduite de un.if X[1:]
est plus court pourif len(X)>1
.Tester:
cumsum([4,6,12]) #[4, 10, 22] cumsum([]) #[]
Et simulaire pour le produit cumulatif:
cumprod = lambda X: X[:1] + cumprod([X[0]*X[1]] + X[2:]) if X[1:] else X
Tester:
cumprod([4,6,12]) #[4, 24, 288]
la source
l = [1,-1,3] cum_list = l def sum_list(input_list): index = 1 for i in input_list[1:]: cum_list[index] = i + input_list[index-1] index = index + 1 return cum_list print(sum_list(l))
la source
Voici une autre solution amusante. Cela tire parti du
locals()
dict d'une compréhension, c'est-à-dire des variables locales générées à l'intérieur de la portée de compréhension de liste:>>> [locals().setdefault(i, (elem + locals().get(i-1, 0))) for i, elem in enumerate(time_interval)] [4, 10, 22]
Voici à quoi
locals()
ressemble chaque itération:>>> [[locals().setdefault(i, (elem + locals().get(i-1, 0))), locals().copy()][1] for i, elem in enumerate(time_interval)] [{'.0': <enumerate at 0x21f21f7fc80>, 'i': 0, 'elem': 4, 0: 4}, {'.0': <enumerate at 0x21f21f7fc80>, 'i': 1, 'elem': 6, 0: 4, 1: 10}, {'.0': <enumerate at 0x21f21f7fc80>, 'i': 2, 'elem': 12, 0: 4, 1: 10, 2: 22}]
Les performances ne sont pas terribles pour les petites listes:
>>> %timeit list(accumulate([4, 6, 12])) 387 ns ± 7.53 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) >>> %timeit np.cumsum([4, 6, 12]) 5.31 µs ± 67.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) >>> %timeit [locals().setdefault(i, (e + locals().get(i-1,0))) for i,e in enumerate(time_interval)] 1.57 µs ± 12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Et tombe évidemment à plat pour les listes plus grandes.
>>> l = list(range(1_000_000)) >>> %timeit list(accumulate(l)) 95.1 ms ± 5.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> %timeit np.cumsum(l) 79.3 ms ± 1.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> %timeit np.cumsum(l).tolist() 120 ms ± 1.23 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> %timeit [locals().setdefault(i, (e + locals().get(i-1, 0))) for i, e in enumerate(l)] 660 ms ± 5.14 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Même si la méthode est moche et peu pratique, elle est certainement amusante.
la source
lst = [4,6,12] [sum(lst[:i+1]) for i in xrange(len(lst))]
Si vous cherchez une solution plus efficace (des listes plus grandes?), Un générateur pourrait être un bon choix (ou simplement utiliser
numpy
si vous vous souciez vraiment de la performance).def gen(lst): acu = 0 for num in lst: yield num + acu acu += num print list(gen([4, 6, 12]))
la source
Ce serait à la 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])
la source