2009-06-23 19 views
28

Eventuali duplicati:
python dict.add_by_value(dict_2) ?"Aggiungere" dizionari in Python?

il mio ingresso è di due dizionari che hanno le chiavi stringa e valori interi. Voglio aggiungere i due dizionari in modo che il risultato abbia tutte le chiavi dei dizionari di input e che i valori siano la somma dei valori dei dizionari di input.

Per chiarezza, se una chiave appare solo in uno degli ingressi, quella chiave/valore apparirà nel risultato, mentre se il tasto appare in entrambi i dizionari, la somma dei valori apparirà nel risultato.

Ad esempio, diciamo che il mio ingresso è:

a = dict() 
a['cat'] = 1 
a['fish'] = 10 
a['aardvark'] = 1000 

b = dict() 
b['cat'] = 2 
b['dog'] = 200 
b['aardvark'] = 2000 

vorrei che il risultato sia:

{'cat': 3, 'fish': 10, 'dog': 200, 'aardvark': 3000} 

Conoscere Python ci deve essere un one-liner per ottenere questo fatto (che doesn 'Devo davvero essere una linea ...). qualche idea?

+1

La domanda è duplicato, le risposte non sono ;-) – Juergen

+0

@msanders: In realtà non è un duplicato, la questione si fa riferimento a tutti i dizionari necessari per avere esattamente le stesse chiavi –

risposta

50

Che ne dici:

dict([ (n, a.get(n, 0)+b.get(n, 0)) for n in set(a)|set(b) ]) 

O senza creare una lista intermedia (generatore è sufficiente):

dict((n, a.get(n, 0)+b.get(n, 0)) for n in set(a)|set(b)) 

Post Scriptum:

come commentatore indirizzato correttamente, c'è un modo di attuare tale più facile con il nuovo (da Py2.7) Classe collections.Counter. Per quanto mi ricordo, questa versione non era disponibile quando ho scritto la risposta:

from collections import Counter 
dict(Counter(a)+Counter(b)) 
+1

+1 bello, anche se le parentesi quadre non sono necessarie in quanto dict() prenderà un generatore – cobbal

+0

Giusto! Solo un'abitudine di me. L'ho visto dopo. – Juergen

+2

+1: nice one-liner. Tuttavia, farei impostare (a) .union (b), in modo da non creare un insieme intermedio [set (b)]. – EOL

15

risultato in a:

for elem in b: 
    a[elem] = a.get(elem, 0) + b[elem] 

risultato in c:

c = dict(a) 
for elem in b: 
    c[elem] = a.get(elem, 0) + b[elem] 
+1

Si tratta di due linee btw :) – Aamir

+6

Non un one-liner, ma il più facile da leggere. +1 –

+0

In questo caso, due righe sono meglio di una. –

15
Non

in una sola riga, ma ...

import itertools 
import collections 
a = dict() 
a['cat'] = 1 
a['fish'] = 10 
a['aardvark'] = 1000 
b = dict() 
b['cat'] = 2 
b['dog'] = 200 
b['aardvark'] = 2000 
c = collections.defaultdict(int) 
for k, v in itertools.chain(a.iteritems(), b.iteritems()): 
    c[k] += v 

Si può facilmente estendere ad un maggior numero di dizionari .

+0

itertools.chain è una bella soluzione, quando è richiesta la massima velocità, poiché nella mia soluzione viene creato un set temporaneo. Suppongo che la catena sia più veloce per i grandi dittici. – Juergen

+0

Beh, non l'ho usato per la velocità qui. Semplicemente non ho bisogno di controllare se ci sono elementi da un mancante in b e viceversa. –

4

Un solo liner (come richiesto): ottiene gli elenchi chiave, li aggiunge, elimina i duplicati, itera sul risultato con la comprensione delle liste, restituisce (chiave, valore) le coppie per la somma se la chiave è in entrambi i dict, o solo il valori individuali se non. Avvolgere in dict.

>>> dict([(x,a[x]+b[x]) if (x in a and x in b) else (x,a[x]) if (x in a) else (x,b[x]) for x in set(a.keys()+b.keys())]) 
{'aardvark': 3000, 'fish': 10, 'dog': 200, 'cat': 3} 
Problemi correlati