time_interval = [4, 6, 12]
Saya ingin merangkum angka-angka seperti [4, 4+6, 4+6+12]
untuk mendapatkan daftarnya t = [4, 10, 22]
.
Saya mencoba yang berikut ini:
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
pengguna2259323
sumber
sumber
Jawaban:
Jika Anda melakukan banyak pekerjaan numerik dengan array seperti ini, saya sarankan
numpy
, yang dilengkapi dengan fungsi penjumlahan kumulatifcumsum
:import numpy as np a = [4,6,12] np.cumsum(a) #array([4, 10, 22])
Numpy seringkali lebih cepat daripada python murni untuk hal semacam ini, lihat dibandingkan dengan @ 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
Tapi tentu saja jika itu satu-satunya tempat Anda akan menggunakan numpy, mungkin tidak ada gunanya bergantung padanya.
sumber
np.cumsun
kasus yang dimulai dengan daftar, untuk memperhitungkan waktu konversi.list
saya tidak akan merekomendasikannumpy
.timeit
, "jika-n
tidak diberikan, jumlah pengulangan yang sesuai dihitung dengan mencoba pangkat 10 berturut-turut hingga total waktu setidaknya 0,2 detik." Jika Anda mengharapkannya untuk membuat perbedaan, Anda dapat menyediakan-n 1000
untuk membuat semuanya setara.Di Python 2 Anda dapat menentukan fungsi generator Anda sendiri seperti ini:
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]
Dan dengan Python 3.2+ Anda dapat menggunakan
itertools.accumulate()
:In [1]: lis = [4,6,12] In [2]: from itertools import accumulate In [3]: list(accumulate(lis)) Out[3]: [4, 10, 22]
sumber
total = 0; partial_sums = [total := total + v for v in values]
. Saya masih berharapaccumulate
bisa lebih cepat.Melihat:
a = [4, 6, 12] reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]
Akan menghasilkan (seperti yang diharapkan):
[4, 10, 22]
sumber
c + [c[-1] + x]
berulang-ulang menambahkan hingga total kuadrat waktu proses dalam panjang input.Saya melakukan benchmark dari dua jawaban teratas dengan Python 3.4 dan saya menemukan
itertools.accumulate
lebih cepat daripadanumpy.cumsum
dalam banyak keadaan, seringkali jauh lebih cepat. Namun, seperti yang Anda lihat dari komentar, mungkin tidak selalu demikian, dan sulit untuk menjelajahi semua opsi secara mendalam. (Jangan ragu untuk menambahkan komentar atau mengedit posting ini jika Anda memiliki hasil benchmark lebih lanjut yang menarik.)Beberapa pengaturan waktu ...
Untuk daftar pendek
accumulate
sekitar 4 kali lebih cepat: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
Untuk daftar yang lebih panjang
accumulate
sekitar 3 kali lebih cepat:l = [1, 2, 3, 4, 5]*1000 timeit(lambda: sum1(l), number=100000) # 19.174508565105498 timeit(lambda: sum2(l), number=100000) # 61.871223849244416
Jika
numpy
array
tidak ditransmisikanlist
,accumulate
masih sekitar 2 kali lebih cepat: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
Jika Anda meletakkan impor di luar kedua fungsi dan masih mengembalikan a
numpy
array
,accumulate
masih hampir 2 kali lebih cepat: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
sumber
list
dari lima item, terutama jika Anda tidak ingin menerima sebagaiarray
gantinya. Jika daftar yang dipermasalahkan sangat pendek, maka waktu berjalannya tidak akan berpengaruh - ketergantungan dan keterbacaan pasti akan mendominasi. Tetapi penggunaan yang luas darilist
tipe data numerik seragam dengan panjang yang signifikan akan menjadi konyol; untuk itu, numpyarray
akan cocok, dan biasanya lebih cepat.numpy
lebih cepat, kecuali saya telah melewatkan sesuatu?sum2
fungsi Anda mungkin diubahl
menjadi array. Coba waktua = np.array(l)
dannp.cumsum(a)
secara terpisah. Kemudian mencobaa = np.tile(np.arange(1, 6), 1000)
vsl = [1,2,3,4,5]*1000
. Dalam program yang melakukan proses numerik lain (seperti pembuatan atau pemuatanl
di tempat pertama) data kerja Anda mungkin sudah ada dalam array, dan pembuatannya akan menjadi biaya konstan.Coba ini: fungsi akumulasi, bersama dengan penambahan operator melakukan penambahan yang berjalan.
import itertools import operator result = itertools.accumulate([1,2,3,4,5], operator.add) list(result)
sumber
operator.add
karena operasi default adalah penambahan.Ekspresi tugas dari PEP 572 (baru di Python 3.8) menawarkan cara lain untuk menyelesaikan ini:
time_interval = [4, 6, 12] total_time = 0 cum_time = [total_time := total_time + t for t in time_interval]
sumber
Anda dapat menghitung daftar jumlah kumulatif dalam waktu linier dengan
for
loop sederhana :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]
Pustaka standar
itertools.accumulate
mungkin merupakan alternatif yang lebih cepat (karena diimplementasikan di C):from itertools import accumulate time_interval = [4, 6, 12] print(list(accumulate(time_interval))) # [4, 10, 22]
sumber
values = [4, 6, 12] total = 0 sums = [] for v in values: total = total + v sums.append(total) print 'Values: ', values print 'Sums: ', sums
Menjalankan kode ini memberi
Values: [4, 6, 12] Sums: [4, 10, 22]
sumber
Di Python3, Untuk mencari jumlah kumulatif dari daftar di mana
i
elemen th adalah jumlah dari elemen i + 1 pertama dari daftar asli, Anda dapat melakukan:a = [4 , 6 , 12] b = [] for i in range(0,len(a)): b.append(sum(a[:i+1])) print(b)
ATAU Anda dapat menggunakan pemahaman daftar:
b = [sum(a[:x+1]) for x in range(0,len(a))]
Keluaran
[4,10,22]
sumber
Jika Anda menginginkan cara pythonic tanpa numpy bekerja di 2.7 ini akan menjadi cara saya melakukannya
l = [1,2,3,4] _d={-1:0} cumsum=[_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)]
sekarang mari kita coba dan mengujinya terhadap semua implementasi lainnya
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
sumber
Mungkin ada banyak jawaban untuk ini tergantung pada panjang daftar dan kinerjanya. Satu cara yang sangat sederhana yang dapat saya pikirkan tanpa memikirkan pertunjukannya adalah ini:
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]
Ini dengan menggunakan pemahaman daftar dan ini mungkin bekerja cukup baik hanya saja di sini saya menambahkan subarray berkali-kali, Anda mungkin bisa berimprovisasi pada ini dan membuatnya sederhana!
Bersulang untuk usaha Anda!
sumber
Pertama, Anda ingin menjalankan daftar selanjutnya:
subseqs = (seq[:i] for i in range(1, len(seq)+1))
Kemudian Anda cukup memanggil
sum
setiap berikutnya:sums = [sum(subseq) for subseq in subseqs]
(Ini bukan cara yang paling efisien untuk melakukannya, karena Anda menambahkan semua awalan berulang kali. Tapi itu mungkin tidak masalah untuk sebagian besar kasus penggunaan, dan lebih mudah untuk dipahami jika Anda tidak perlu memikirkan total lari.)
Jika Anda menggunakan Python 3.2 atau yang lebih baru, Anda dapat menggunakannya
itertools.accumulate
untuk Anda:Dan jika Anda menggunakan 3.1 atau sebelumnya, Anda dapat langsung menyalin sumber "setara dengan" dari dokumen (kecuali untuk mengubah
next(it)
keit.next()
untuk 2.5 dan sebelumnya).sumber
range
daripada[1:]
[4,6,12]
karena, seperti yang dia tulis di pertanyaan, dia sudah tahu apa itu!Coba ini:
result = [] acc = 0 for i in time_interval: acc += i result.append(acc)
sumber
In [42]: a = [4, 6, 12] In [43]: [sum(a[:i+1]) for i in xrange(len(a))] Out[43]: [4, 10, 22]
Ini adalah slighlty lebih cepat daripada metode pembangkit di atas dengan @Ashwini untuk daftar kecil
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
Untuk daftar yang lebih besar, generator adalah cara yang pasti. . .
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
sumber
Agak hacky, tetapi sepertinya berhasil:
def cumulative_sum(l): y = [0] def inc(n): y[0] += n return y[0] return [inc(x) for x in l]
Saya memang berpikir bahwa fungsi bagian dalam akan dapat memodifikasi yang
y
dideklarasikan di lingkup leksikal luar, tetapi itu tidak berhasil, jadi kami memainkan beberapa peretasan jahat dengan modifikasi struktur sebagai gantinya. Mungkin lebih elegan menggunakan generator.sumber
Tanpa harus menggunakan Numpy, Anda dapat melakukan loop langsung pada array dan mengakumulasikan jumlahnya di sepanjang jalan. Sebagai contoh:
a=range(10) i=1 while((i>0) & (i<10)): a[i]=a[i-1]+a[i] i=i+1 print a
Hasil dalam:
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
sumber
Oneliner python murni untuk jumlah kumulatif:
cumsum = lambda X: X[:1] + cumsum([X[0]+X[1]] + X[2:]) if X[1:] else X
Ini adalah versi rekursif yang terinspirasi oleh jumlah kumulatif rekursif . Beberapa penjelasannya:
X[:1]
adalah daftar yang berisi elemen sebelumnya dan hampir sama[X[0]]
(yang akan dikeluhkan untuk daftar kosong).cumsum
Panggilan rekursif dalam istilah kedua memproses elemen saat ini[1]
dan daftar yang tersisa yang panjangnya akan dikurangi satu.if X[1:]
lebih pendek untukif len(X)>1
.Uji:
cumsum([4,6,12]) #[4, 10, 22] cumsum([]) #[]
Dan simular untuk produk kumulatif:
cumprod = lambda X: X[:1] + cumprod([X[0]*X[1]] + X[2:]) if X[1:] else X
Uji:
cumprod([4,6,12]) #[4, 24, 288]
sumber
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))
sumber
Inilah solusi menyenangkan lainnya. Ini mengambil keuntungan dari
locals()
diktik pemahaman, yaitu variabel lokal yang dihasilkan di dalam cakupan pemahaman daftar:>>> [locals().setdefault(i, (elem + locals().get(i-1, 0))) for i, elem in enumerate(time_interval)] [4, 10, 22]
Berikut
locals()
tampilan untuk setiap iterasi:>>> [[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}]
Performa tidak buruk untuk daftar kecil:
>>> %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)
Dan jelas tidak cocok untuk daftar yang lebih besar.
>>> 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)
Meski metodenya jelek dan tidak praktis, itu pasti menyenangkan.
sumber
lst = [4,6,12] [sum(lst[:i+1]) for i in xrange(len(lst))]
Jika Anda mencari solusi yang lebih efisien (daftar yang lebih besar?), Generator bisa menjadi pilihan yang baik (atau hanya digunakan
numpy
jika Anda benar-benar peduli dengan kinerja).def gen(lst): acu = 0 for num in lst: yield num + acu acu += num print list(gen([4, 6, 12]))
sumber
Ini akan menjadi gaya 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])
sumber