2013-11-26 32 views
8

Qual è il modo migliore per replicare questa semplice funzione utilizzando una list comprehension (o un altro approccio compatto)?Comprensione delle liste con un accumulatore

import numpy as np 

sum=0 
array=[] 
for i in np.random.rand(100): 
    sum+=i 
    array.append(sum) 
+0

Stai usando NumPy per caso? So che Numpy ha una buona funzione per qualcosa di simile. – arshajii

+1

Non userei la comprensione di una lista - ci si aspetta che gli elementi siano indipendenti l'uno dall'altro, e in questo caso non lo sono. – Izkata

+1

Perché vorresti trasformare questo in una comprensione di lista? È molto più leggibile tenere questo in un ciclo separato. Rendilo 'array = [0]', 'for i in rand (100): array.append (i + array [-1])' invece, forse. –

risposta

6

In Python 3, utilizza itertools.accumulate():

from itertools import accumulate 

array = list(accumulate(rand(100))) 

Accumulate produce il risultato di esecuzione di sommando i valori dell'ingresso iterabile, a partire dal primo valore:

>>> from itertools import accumulate 
>>> list(accumulate(range(10))) 
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45] 

È possibile passare a un'altra operazione come secondo argomento; questo dovrebbe essere un callable che prende il risultato accumulato e il valore successivo, restituendo il nuovo risultato accumulato. Il operator module è molto utile per fornire operatori matematici standard per questo tipo di lavoro; si potrebbe usare per produrre una corsa moltiplicazione provocare ad esempio:

>>> import operator 
>>> list(accumulate(range(1, 10), operator.mul)) 
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880] 

La funzionalità è abbastanza facile da backport di versioni più vecchie (Python 2, o Python 3.0 o 3.1):

# Python 3.1 or before 

import operator 

def accumulate(iterable, func=operator.add): 
    'Return running totals' 
    # accumulate([1,2,3,4,5]) --> 1 3 6 10 15 
    # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120 
    it = iter(iterable) 
    total = next(it) 
    yield total 
    for element in it: 
     total = func(total, element) 
     yield total 
+0

Questo funziona ma stavo cercando qualcosa come una lista di comprensione per l'uso compatto, come nella riga di comando di ipython. – Pierz

+0

@Pierz: ho usato 'list()' sull''iteratore 'accumulate()' per darti un rapido elenco di valori. Puoi ancora usarlo anche in una list comprehension, '[v per v in accumulate (rand (100))]'; non puoi farlo con * solo * una comprensione delle liste, perché non hai accesso agli elementi precedenti generati finora. –

+0

Vero è un approccio elegante ma non ero sicuro se ci fosse un modo pulito per avere la somma accumulata in una lista di comprensione. D'accordo, probabilmente non è una buona pratica, ma quando si lavora sulla riga di comando è utile usare moduli compatti. – Pierz

4

Since You stiamo già utilizzando numpy, è possibile utilizzare cumsum:

>>> from numpy.random import rand 
>>> x = rand(10) 
>>> x 
array([ 0.33006219, 0.75246128, 0.62998073, 0.87749341, 0.96969786, 
     0.02256228, 0.08539008, 0.83715312, 0.86611906, 0.97415447]) 
>>> x.cumsum() 
array([ 0.33006219, 1.08252347, 1.7125042 , 2.58999762, 3.55969548, 
     3.58225775, 3.66764783, 4.50480095, 5.37092001, 6.34507448]) 
1

Ok, hai detto che non volevi numpy ma qui è la mia soluzione in ogni caso. Mi sembra che stai semplicemente prendendo la somma cumulativa, quindi utilizza la funzione cumsum().

import numpy as np 
result = np.cumsum(some_array) 

Per un esempio a caso

result = np.cumsum(np.random.uniform(size=100)) 
Problemi correlati