python: encuentra solo pares clave-valor comunes de varios dictados: intersección de dict

Tengo 0 o más dictados en una lista:

>>> dicts = [dict(a=3, b=89, d=2), dict(a=3, b=89, c=99), dict(a=3, b=42, c=33)] 

Quiero crear un nuevo dict que contenga solo claves que estén en todos los dictados anteriores, y solo si los valores son todos iguales:

 >>> dict_intersection(*dicts) {"a": 3} 

Siento que debería haber una manera elegante de escribir dict_intersection , pero solo estoy encontrando soluciones poco elegantes y / o ineficientes. Sugerencias?

 >>> dict(set.intersection(*(set(d.iteritems()) for d in dicts))) {'a': 3} 

Nota: esta solución requiere que los valores del diccionario sean hashable, además de las claves.

Como los pares clave / valor ya deben estar en el primer dictado, puede iterar sobre los elementos de este dictado.

 dict(pair for pair in dicts[0].items() if all((pair in d.items() for d in dicts[1:]))) 

Parece menos elegante que la respuesta de Interjay, pero funciona sin la restricción de los valores de hashable.

Edición: se cambió la expresión de all a una expresión de generador para mejorar la velocidad

¿Cómo es esto?

 def intersect_two_dicts (d1, d2): return { k:v for k,v in d1.iteritems() if ((k in d2)and(d1[k]==d2[k])) } def intersect_dicts (list_of_dicts): return reduce(intersect_two_dicts, list_of_dicts) # Tests dicts = [dict(a=3, b=89, d=2), dict(a=3, b=89, c=99), dict(a=3, b=42, c=33)] print (intersect_two_dicts(dicts[0], dicts[1])) print (intersect_dicts(dicts)) 

Editar (1): No estoy seguro de cuál de estos es el más rápido. Las soluciones set.intersection son sin duda las más elegantes (¡una línea corta !), Pero me gustaría ver algunos puntos de referencia.

Edit (2): Bonus: obtenga cualquier entrada de diccionario cuyos pares (clave: valor) sean comunes a cualquiera de los dos diccionarios:

 {k:count for k,count in collections.Counter(itertools.chain(*[d.iteritems() for d in dicts])).iteritems() if count > 1} 
 >>> dicts [{'a': 3, 'b': 89, 'd': 2}, {'a': 3, 'c': 99, 'b': 89}, {'a': 3, 'c': 33, 'b': 42}] >>> sets = (set(d.iteritems()) for d in dicts) >>> dict_intersection = dict(set.intersection(*sets)) >>> dict_intersection {'a': 3} 

Un enfoque un poco más sucio: tome la lista de claves para cada diccionario, ordene cada lista y luego proceda como si las estuviera fusionando (mantenga un índice para cada lista, avance el valor más bajo). Cuando todos los índices apuntan a la misma clave, verifique la igualdad de los valores; De cualquier manera, avanza todos los índices.