2009-06-23 16 views
28

Duplicar posible:
python dict.add_by_value(dict_2) ?"Agregar" Diccionarios en Python?

Mi entrada es dos diccionarios que tienen claves de cadena y valores enteros. Quiero agregar los dos diccionarios para que el resultado tenga todas las claves de los diccionarios de entrada, y los valores son la suma de los valores de los diccionarios de entrada.

Para mayor claridad, si una tecla aparece solo en una de las entradas, esa clave/valor aparecerá en el resultado, mientras que si la tecla aparece en ambos diccionarios, la suma de valores aparecerá en el resultado.

Por ejemplo, decir que mi entrada es:

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

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

me gustaría que el resultado sea:

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

Conociendo Python debe haber una sola línea para hacer esto (que doesn realmente tiene que ser una línea ...). ¿Alguna idea?

+1

La pregunta es duplicado, las respuestas no son ;-) – Juergen

+0

@msanders: En realidad no es un duplicado, la pregunta que usted se refiere a todos los diccionarios necesarios para tener exactamente las mismas claves –

Respuesta

50

¿Qué tal que:

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

o sin la creación de una lista intermedia (generador es suficiente):

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

Post Data:

Como comentarista dirigida correctamente, no es una forma de implementar que más fácil con el nuevo (de Py2.7) collections.Counter clase. Por mucho que recuerdo, esta versión no estaba disponible cuando escribí la respuesta:

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

+1 bueno, aunque los corchetes no son necesarios ya que dict() tomará un generador – cobbal

+0

¡Eso es correcto! Solo un hábito de mi parte. Lo vi después. – Juergen

+2

+1: buen trazador de líneas. Sin embargo, establecería (a) .union (b), para no crear un conjunto intermedio [set (b)]. – EOL

15

resultado en a:

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

resultado en c:

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

se trata de dos líneas por cierto :) – Aamir

+6

No es un trazador de líneas, pero el más fácil de leer. +1 –

+0

En este caso, dos líneas es mejor que una. –

15
No

en una sola línea, pero ...

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 

Se puede extender fácilmente a un mayor número de diccionarios .

+0

itertools.chain es una buena solución, cuando se necesita velocidad máxima, ya que en mi solución se crea un conjunto temporal. Supongo que la cadena es más rápida para los grandes dicts. – Juergen

+0

Bueno, no lo usé para la velocidad aquí. Simplemente no necesito verificar si hay elementos de a que faltan en by viceversa. –

4

One liner (como sortof requested): obtener listas de teclas, agregarlas, descartar duplicados, iterar sobre el resultado con comprensión de lista, pares de retorno (clave, valor) para la suma si la clave está en ambos dicts, o solo valores individuales si no. Ajustar en 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} 
Cuestiones relacionadas