2015-09-09 7 views
5

Ho una lista da cui ho bisogno di rimuovere i valori duplicati e sommare i valori delle colonne corrispondenti. La lista è:Rimuovere i valori duplicati e sommare i valori delle colonne corrispondenti

lst = [['20150815171000', '1', '2'], 
     ['20150815171000', '2', '3'], 
     ['20150815172000', '3', '4'], 
     ['20150815172000', '4', '5'], 
     ['20150815172000', '5', '6'], 
     ['20150815173000', '6', '7']] 

ora ho bisogno di attraversare l'elenco e ottenere l'output qualcosa di simile:

lst2 = [['20150815171000', '3', '5'], 
     ['20150815172000', '12', '15'], 
     ['20150815173000', '6', '7']] 

Come potrebbe questo essere fatto? Ho provato a scrivere il codice come mostrato di seguito, ma è solo il confronto con valori consecutivi non, non tutti quelli abbinati.

Qualcuno può farmi sapere come posso fare questo?

+0

creare un dizionario, a partire per esempio '{'20150815171000': ['1', '2']}', quindi riconvertirli in un elenco successivo – jonrsharpe

+0

L'output di esempio ha il valore somme come stringhe, ma il codice le rende mobili. Allora, cosa vuoi veramente, stringhe o galleggianti? –

risposta

5

Vorrei utilizzare itertools.groupby, raggruppamento basato sul primo elemento nell'elenco interno.

Quindi vorrei prima ordinare l'elenco in base al primo elemento e quindi raggrupparlo in base ad esso (se l'elenco fosse già ordinato su quell'elemento, non è necessario ordinare nuovamente, è possibile raggruppare direttamente).

Esempio -

new_lst = [] 
for k,g in itertools.groupby(sorted(lst,key=lambda x:x[0]) , lambda x:x[0]): 
    l = list(g) 
    new_lst.append([k,str(sum([int(x[1]) for x in l])), str(sum([int(x[2]) for x in l]))]) 

Demo -

>>> import itertools 
>>> 
>>> lst = [['20150815171000', '1', '2'], 
...  ['20150815171000', '2', '3'], 
...  ['20150815172000', '3', '4'], 
...  ['20150815172000', '4', '5'], 
...  ['20150815172000', '5', '6'], 
...  ['20150815173000', '6', '7']] 
>>> 
>>> new_lst = [] 
>>> for k,g in itertools.groupby(sorted(lst,key=lambda x:x[0]) , lambda x:x[0]): 
...  l = list(g) 
...  new_lst.append([k,str(sum([int(x[1]) for x in l])), str(sum([int(x[2]) for x in l]))]) 
... 
>>> new_lst 
[['20150815171000', '3', '5'], ['20150815172000', '12', '15'], ['20150815173000', '6', '7']] 
+0

Grazie mille, ha funzionato. @ Anand S Kumar –

+2

Felice che abbia funzionato per voi. Vorrei anche chiederti di accettare una risposta, (cliccando sul segno di spunta sul lato sinistro della risposta). Sarebbe utile per la comunità. –

3

È possibile utilizzare un dizionario per gestire voci univoche nella vostra lista. Quindi si controlla se una chiave già contenuta nei tasti del dict. Se la chiave è già nella dict, aggiungere a quella attuale, altrimenti aggiungere una nuova voce al dett.

Prova questo:

#!/usr/bin/env python3 

sums = dict() 
for key, *values in lst: 
    try: 
     # add to an already present entry in the dict 
     sums[key] = [int(x)+y for x, y in zip(values, sums[key])] 
    except KeyError: 
     # if the entry is not already present add it to the dict 
     # and cast the values to int to make the adding easier 
     sums[key] = map(int, values) 

# build the output list from dictionary 
# also cast back the values to strings 
lst2 = sorted([[key]+list(map(str, values)) for key, values in sums.items()]) 

Il sorted nell'ultima riga potrebbe essere facoltativo. A seconda che sia necessario ordinare l'elenco di output in base ai tasti dict o meno.

Si noti che questo dovrebbe funzionare per qualsiasi lunghezza di valori dopo il tasto.

+0

Splendidamente fatto – The6thSense

1

Come commentato sulla tua domanda, vorrei anche suggerire di usare un dizionario per aiuto. Io non sono un buon programmatore e là un certo modi migliori, ma questo funziona:

dct = dict() 
for x, y, z in lst: 
    if x not in dct: 
     dct[x] = [y, z] 
    else: 
     dct[x] = [str(int(dct[x][0]) + int(y)), str(int(dct[x][1]) + int(z))] 
lst2 = [] 
for k, v in dct.items(): 
    lst2.append([k, v[0], v[1]]) 

Si sono fondamentalmente solo l'iterazione della lista e, l'aggiunta di un nuovo elemento al dizionario se il numero desiderato (ad esempio '2.015.081,5171 milioni ') non esiste ancora, altrimenti aggiorna i valori corrispondenti. Alla fine basta creare un altro elenco di risultati nel dizionario

2

In alternativa, vi suggerirei di usare pandas, abbastanza semplice con i groupby e sum, qui è un modo per farlo:

In [1]: import pandas as pd 

In [2]: df = pd.DataFrame(
[['20150815171000', '1', '2'], 
['20150815171000', '2', '3'], 
['20150815172000', '3', '4'], 
['20150815172000', '4', '5'], 
['20150815172000', '5', '6'], 
['20150815173000', '6', '7']], 
columns=['group', 'field1', 'field2']) 

In [3]: df 
Out[3]: 
      group field1 field2 
0 20150815171000  1  2 
1 20150815171000  2  3 
2 20150815172000  3  4 
3 20150815172000  4  5 
4 20150815172000  5  6 
5 20150815173000  6  7 

# need to convert from '1', '2'... to integer type 
In [4]: df['field1'] = df['field1'].astype('int') 

In [5]: df['field2'] = df['field2'].astype('int') 

# this groupby(to_group_field) and sum() can achieve what you want 
In [6]: df.groupby('group').sum() 
Out[6]: 
       field1 field2 
group 
20150815171000  3  5 
20150815172000  12  15 
20150815173000  6  7 

# convert to the list of lists format as you expected 
In [7]: df.groupby('group').sum().reset_index().values.tolist() 
Out[7]: 
[['20150815171000', 3, 5], 
['20150815172000', 12, 15], 
['20150815173000', 6, 7]] 

Spero che questo ti aiuti.

2

Pulire con lambda e ordinati() utilizzando il dizionario. Senza librerie aggiuntive.

lst = [['20150815171000', '1', '2'], 
     ['20150815171000', '2', '3'], 
     ['20150815172000', '3', '4'], 
     ['20150815172000', '4', '5'], 
     ['20150815172000', '5', '6'], 
     ['20150815173000', '6', '7']] 

dct = dict() 
for a, b, c in lst: 
    if a not in dct: 
     dct[a] = [b, c] 
    else: 
     dct[a] = map(lambda x, y: str(int(x)+int(y)), dct[a], [b,c]) 
lst2 = sorted([[k,v[0],v[1]] for k,v in dct.items()]) 

print(lst2) 

Out:

[['20150815171000', '3', '5'], 
['20150815172000', '12', '15'], 
['20150815173000', '6', '7']]