2012-07-25 11 views
7

Diciamo Ho le seguenti due liste di tuplePython Modo più semplice per Somma Lista Intersezione di lista di tuple

myList = [(1, 7), (3, 3), (5, 9)] 
otherList = [(2, 4), (3, 5), (5, 2), (7, 8)] 

returns => [(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)] 

Vorrei progettare un'operazione di unione che unisce queste due liste per la verifica di eventuali incroci il primo elemento della tupla, se ci sono intersezioni, aggiungi i secondi elementi di ogni tupla in questione (unisci i due). Dopo l'operazione vorrei ordinare in base al primo elemento.

Inoltre sto postando questo perché penso che sia un problema abbastanza comune che ha una soluzione ovvia, ma sento che ci potrebbero essere soluzioni molto divinatorio a questa domanda;)

risposta

14

utilizzare un dizionario per il risultato:

result = {} 
for k, v in my_list + other_list: 
    result[k] = result.get(k, 0) + v 

Se si desidera un elenco di tuple, è possibile farlo tramite result.items(). L'elenco risultante sarà in ordine arbitrario, ma ovviamente è possibile ordinarlo se lo si desidera.

(. Si noti che ho rinominato le vostre liste per conformarsi con le convenzioni di stile di Python)

+0

Davvero pulito. Bella soluzione! –

+0

Nota che 'result.items()' restituirà un oggetto 'dict_items' in Python 3. Ovviamente puoi sempre fare' list (result.items()) '. – kamek

1

un metodo che utilizza itertools:

>>> myList = [(1, 7), (3, 3), (5, 9)] 
>>> otherList = [(2, 4), (3, 5), (5, 2), (7, 8)] 

>>> import itertools 
>>> merged = [] 
>>> for k, g in itertools.groupby(sorted(myList + otherList), lambda e: e[0]): 
... merged.append((k, sum(e[1] for e in g))) 
... 
>>> merged 
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)] 

Questa prima concatena i due liste insieme e lo ordina in. itertools.groupby restituisce gli elementi dell'elenco unito, raggruppati in base al primo elemento della tupla, quindi li riassume e li inserisce nell'elenco unito.

4

Uso defaultdict:

from collections import defaultdict 
results_dict = defaultdict(int) 
results_dict.update(my_list) 
for a, b in other_list: 
    results_dict[a] += b 
results = sorted(results_dict.items()) 

Nota: Quando si ordina sequenze, sorted sorta da parte del primo elemento della sequenza. Se i primi elementi sono uguali, confronta il secondo elemento. Si può dare sorted una funzione per ordinare, utilizzando la parola chiave key argomento:

results = sorted(results_dict.items(), key=lambda x: x[1]) #sort by the 2nd item 

o

results = sorted(results_dict.items(), key=lambda x: abs(x[0])) #sort by absolute value 
+0

(+1) Non so come tutto questo tempo non mi rendo conto che 'dict.update' accetta una sequenza uguale al costruttore di dict. Inoltre, è banale ordinare sul primo elemento della tupla come richiesto dall'OP ('results = sorted (results_dict.items())') – mgilson

+0

@ mgilson: Grazie! Ho perso la parte relativa a un risultato ordinato. Modificherà. –

+0

@mgilson: Apparentemente 'update()' accetta iterabili è stato introdotto in 2.4. –

0
>>> [(k, sum(v for x,v in myList + otherList if k == x)) for k in dict(myList + otherList).keys()] 
[(1, 7), (2, 4), (3, 8), (5, 11), (7, 8)] 
>>> 

controllato in relazione sia Python2.7 e 3.2
dict(myList + otherList).keys() restituisce un iterabile contenente un set delle chiavi per gli elenchi uniti
sum(...) prende "k" per ripetere il ciclo attraverso l'elenco unito e sommare gli elementi tupla "v" dove k == x

... ma il ciclo aggiuntivo aggiunge l'overhead di elaborazione. L'uso di un dizionario esplicito come proposto da Sven Marnach lo evita.