2016-02-24 10 views
6

cerco di trattare tali dati:Python calcolo in esecuzione somma dei valori in una riga

some_data = [ 
       {'value': 2, 'date':'2016-02-06'}, 
       {'value': 1, 'date':'2016-02-07'}, 
       {'value': 5, 'date':'2016-02-08'}, 
       {'value': 3, 'date':'2016-02-09'}, 
       {'value': 1, 'date':'2016-02-10'}, 
      ] 

in modo da produrre un elenco con i valori aggiornati per essere una somma parziale. Ora lo faccio con un ciclo multilinea:

def values_incremented(some_data): 
    temp_sum = 0 
    result = [] 
    for element in some_data: 
     temp_sum += element['value'] 
     result.append({'value': temp_sum, 'date': element['date']}) 
    return result 

Come fare il loop one-liner, in modo che ho ottenuto:

return [{'value': somehow_incremented, 'date': element['date']} for element in some_data] 
+0

Qual è l'output desiderato? Cosa stai ricevendo al momento? –

+1

@ nathan.meadows: leggi di nuovo la domanda. –

+0

Hai due righe nel ciclo for e vuoi una riga. Ho capito bene? – AlokThakur

risposta

3

non mi consiglia di fare qualsiasi cosa , il codice è bene. Rendilo leggibile.

Detto questo, ecco un approccio:

def values_incremented(some_data): 
    return [{'value': current_sum, 'date': element['date']} 
     for element, current_sum 
     in zip(some_data, 
      reduce(lambda x, y: [y['value']] if not x else x + [x[-1] + y['value']], some_data, []))] 
+0

Questo è un vero e unico rivestimento :) Grazie :) E sì, hai ragione, il codice originale è molto più leggibile. Ciò che ho inteso è stato quello di ridurre le dichiarazioni di riserva, come ad esempio 'temp_sum = 0' e' result = [] ' – alekwisnia

+0

Sì, calcolare la somma cumulativa lo rende scomodo. Ho appena guardato in su ... nessuno di loro ha un aspetto pulito: http://stackoverflow.com/questions/3432830/list-comprehension-for-running-total Se lo estrai, allora va bene, anche se preferirei comunque il tuo codice originale –

6

si potrebbe scrivere anche tu una funzione di generatore di accumulo. Utilizzare send per inviare valori nel generatore e ottenere la nuova somma.

def accumulator(n=0): 
    while True: 
     n += yield n 

acc = accumulator(0) 
acc.send(None) 

res = [{'value': acc.send(element['value']), 'date': element['date']} for element in some_data] 

Di conseguenza, è res

[{'value': 2, 'date': '2016-02-06'}, 
{'value': 3, 'date': '2016-02-07'}, 
{'value': 8, 'date': '2016-02-08'}, 
{'value': 11, 'date': '2016-02-09'}, 
{'value': 12, 'date': '2016-02-10'}] 
+1

Questo è fantastico :-) quindi +1 per quello ... Tuttavia, penso che il ciclo for semplice sia considerevolmente più leggibile. –

1

Ecco un uno di linea che viene eseguito in tempo lineare:

reduce(lambda (c,s), a: (c + [{'value':s+a['value'], 'date':a['date']}], s+a['value']), some_data,([],0))[0] 

>>> [{'date': '2016-02-06', 'value': 2}, 
    {'date': '2016-02-07', 'value': 3}, 
    {'date': '2016-02-08', 'value': 8}, 
    {'date': '2016-02-09', 'value': 11}, 
    {'date': '2016-02-10', 'value': 12}] 

Si dovrebbe guardare il other running total question per una versione più semplice dello stesso problema .