values keys dictionaries create python dictionary

keys - python dictionary of dictionaries



Calcule la diferencia en las claves contenidas en dos diccionarios de Python (21)

Supongamos que tengo dos diccionarios de Python: dictA y dictB . Necesito averiguar si hay claves que están presentes en dictB pero no en dictA . ¿Cuál es la forma más rápida de hacerlo?

¿Debo convertir las teclas del diccionario en un conjunto y luego seguir?

Interesado en conocer tus pensamientos ...

Gracias por tus respuestas.

Disculpas por no decir mi pregunta correctamente. Mi escenario es así: tengo un dictA que puede ser el mismo que dictB o pueden faltar algunas teclas en comparación con dictB o, de lo contrario, el valor de algunas teclas puede ser diferente, que debe establecerse en el valor de la clave dictA .

El problema es que el diccionario no tiene un estándar y puede tener valores que pueden ser dict de dict.

Decir

dictA={''key1'':a, ''key2'':b, ''key3'':{''key11'':cc, ''key12'':dd}, ''key4'':{''key111'':{....}}} dictB={''key1'':a, ''key2:'':newb, ''key3'':{''key11'':cc, ''key12'':newdd, ''key13'':ee}.......

Por lo tanto, el valor ''key2'' debe restablecerse al nuevo valor y debe agregarse ''key13'' dentro del dict. El valor clave no tiene un formato fijo. Puede ser un valor simple o un dict o un dict de dict.


¿qué pasa con standart (comparar Objeto COMPLETO)

PyDev-> nuevo módulo PyDev-> módulo: unittest

import unittest class Test(unittest.TestCase): def testName(self): obj1 = {1:1, 2:2} obj2 = {1:1, 2:2} self.maxDiff = None # sometimes is usefull self.assertDictEqual(d1, d2) if __name__ == "__main__": #import sys;sys.argv = ['''', ''Test.testName''] unittest.main()


@Maxx tiene una respuesta excelente, use las herramientas de prueba unitarias provistas por Python:

import unittest class Test(unittest.TestCase): def runTest(self): pass def testDict(self, d1, d2, maxDiff=None): self.maxDiff = maxDiff self.assertDictEqual(d1, d2)

Luego, en cualquier parte de tu código, puedes llamar:

try: Test().testDict(dict1, dict2) except Exception, e: print e

La salida resultante se parece a la salida de diff , imprimiendo bastante los diccionarios con + o - anteponiendo cada línea que es diferente.


A continuación, creé dos diccionarios. Necesito devolver la clave y valorar las diferencias entre ellos. Estoy atrapado aquí. No estoy seguro de cuál es la forma correcta. Necesito saber cómo obtener la diferencia de valor clave. Primero quiero comprobar si son iguales y si no deben imprimir las diferencias de valores clave. No quiero usar diff profundo No sé para comparar si son lo mismo?

num_list = [1,2] val_list = [0,1] dict1 = dict(zip(num_list,val_list)) print dict1 num_list2= [1,2] val_list2 = [0,6] dict2 = dict(zip(num_list2,val_list2)) print dict2 if dict1 == dict2

salida: actualmente {1: 0, 2: 1} {1: 0, 2: 6}


Aquí hay una solución para comparar profundamente 2 claves de diccionarios:

def compareDictKeys(dict1, dict2): if type(dict1) != dict or type(dict2) != dict: return False keys1, keys2 = dict1.keys(), dict2.keys() diff = set(keys1) - set(keys2) or set(keys2) - set(keys1) if not diff: for key in keys1: if (type(dict1[key]) == dict or type(dict2[key]) == dict) and not compareDictKeys(dict1[key], dict2[key]): diff = True break return not diff


Aquí hay una solución que puede comparar más de dos dictados:

def diff_dict(dicts, default=None): diff_dict = {} # add ''list()'' around ''d.keys()'' for python 3 compatibility for k in set(sum([d.keys() for d in dicts], [])): # we can just use "values = [d.get(k, default) ..." below if # we don''t care that d1[k]=default and d2[k]=missing will # be treated as equal if any(k not in d for d in dicts): diff_dict[k] = [d.get(k, default) for d in dicts] else: values = [d[k] for d in dicts] if any(v != values[0] for v in values): diff_dict[k] = values return diff_dict

ejemplo de uso:

import matplotlib.pyplot as plt diff_dict([plt.rcParams, plt.rcParamsDefault, plt.matplotlib.rcParamsOrig])


Basado en la respuesta de ghostdog74,

dicta = {"a":1,"d":2} dictb = {"a":5,"d":2} for value in dicta.values(): if not value in dictb.values(): print value

imprimirá difieren valor de dicta


Como escribió Alex Martelli, si simplemente quiere comprobar si alguna tecla en B no está en A, any(True for k in dictB if k not in dictA) sería el camino a seguir.

Para encontrar las claves que faltan:

diff = set(dictB)-set(dictA) #sets C:/Dokumente und Einstellungen/thc>python -m timeit -s "dictA = dict(zip(range(1000),range (1000))); dictB = dict(zip(range(0,2000,2),range(1000)))" "diff=set(dictB)-set(dictA)" 10000 loops, best of 3: 107 usec per loop diff = [ k for k in dictB if k not in dictA ] #lc C:/Dokumente und Einstellungen/thc>python -m timeit -s "dictA = dict(zip(range(1000),range (1000))); dictB = dict(zip(range(0,2000,2),range(1000)))" "diff=[ k for k in dictB if k not in dictA ]" 10000 loops, best of 3: 95.9 usec per loop

Entonces esas dos soluciones son más o menos de la misma velocidad.


Como se menciona en otras respuestas, unittest produce una buena salida para comparar dicts, pero en este ejemplo no queremos tener que construir primero una prueba completa.

Al raspar la fuente de la prueba unitaria, parece que puede obtener una solución justa con solo esto:

import difflib import pprint def diff_dicts(a, b): if a == b: return '''' return ''/n''.join( difflib.ndiff(pprint.pformat(a, width=30).splitlines(), pprint.pformat(b, width=30).splitlines()) )

asi que

dictA = dict(zip(range(7), map(ord, ''python''))) dictB = {0: 112, 1: ''spam'', 2: [1,2,3], 3: 104, 4: 111} print diff_dicts(dictA, dictB)

Resultados en:

{0: 112, - 1: 121, - 2: 116, + 1: ''spam'', + 2: [1, 2, 3], 3: 104, - 4: 111, ? ^ + 4: 111} ? ^ - 5: 110}

Dónde:

  • ''-'' indica clave / valores en el primer pero no segundo dict
  • ''+'' indica clave / valores en el segundo pero no en el primer dict

Al igual que en la prueba de unidad, la única advertencia es que la asignación final se puede considerar como una diferencia, debido a la coma / paréntesis final.


En caso de que quiera la diferencia recursivamente, he escrito un paquete para python: https://github.com/seperman/deepdiff

Instalación

Instalar desde PyPi:

pip install deepdiff

Ejemplo de uso

Importador

>>> from deepdiff import DeepDiff >>> from pprint import pprint >>> from __future__ import print_function # In case running on Python 2

El mismo objeto regresa vacío

>>> t1 = {1:1, 2:2, 3:3} >>> t2 = t1 >>> print(DeepDiff(t1, t2)) {}

El tipo de artículo ha cambiado

>>> t1 = {1:1, 2:2, 3:3} >>> t2 = {1:1, 2:"2", 3:3} >>> pprint(DeepDiff(t1, t2), indent=2) { ''type_changes'': { ''root[2]'': { ''newtype'': <class ''str''>, ''newvalue'': ''2'', ''oldtype'': <class ''int''>, ''oldvalue'': 2}}}

El valor de un artículo ha cambiado

>>> t1 = {1:1, 2:2, 3:3} >>> t2 = {1:1, 2:4, 3:3} >>> pprint(DeepDiff(t1, t2), indent=2) {''values_changed'': {''root[2]'': {''newvalue'': 4, ''oldvalue'': 2}}}

Artículo agregado y / o eliminado

>>> t1 = {1:1, 2:2, 3:3, 4:4} >>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff) {''dic_item_added'': [''root[5]'', ''root[6]''], ''dic_item_removed'': [''root[4]''], ''values_changed'': {''root[2]'': {''newvalue'': 4, ''oldvalue'': 2}}}

Diferencia de cadena

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}} >>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { ''values_changed'': { ''root[2]'': {''newvalue'': 4, ''oldvalue'': 2}, "root[4][''b'']": { ''newvalue'': ''world!'', ''oldvalue'': ''world''}}}

Diferencia de cadena 2

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!/nGoodbye!/n1/n2/nEnd"}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world/n1/n2/nEnd"}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { ''values_changed'': { "root[4][''b'']": { ''diff'': ''--- /n'' ''+++ /n'' ''@@ -1,5 +1,4 @@/n'' ''-world!/n'' ''-Goodbye!/n'' ''+world/n'' '' 1/n'' '' 2/n'' '' End'', ''newvalue'': ''world/n1/n2/nEnd'', ''oldvalue'': ''world!/n'' ''Goodbye!/n'' ''1/n'' ''2/n'' ''End''}}} >>> >>> print (ddiff[''values_changed'']["root[4][''b'']"]["diff"]) --- +++ @@ -1,5 +1,4 @@ -world! -Goodbye! +world 1 2 End

Tipo de cambio

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world/n/n/nEnd"}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { ''type_changes'': { "root[4][''b'']": { ''newtype'': <class ''str''>, ''newvalue'': ''world/n/n/nEnd'', ''oldtype'': <class ''list''>, ''oldvalue'': [1, 2, 3]}}}

Lista de diferencia

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) {''iterable_item_removed'': {"root[4][''b''][2]": 3, "root[4][''b''][3]": 4}}

Lista de diferencia 2:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { ''iterable_item_added'': {"root[4][''b''][3]": 3}, ''values_changed'': { "root[4][''b''][1]": {''newvalue'': 3, ''oldvalue'': 2}, "root[4][''b''][2]": {''newvalue'': 2, ''oldvalue'': 3}}}

Listar la diferencia ignorando el orden o duplicar: (con los mismos diccionarios que arriba)

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}} >>> ddiff = DeepDiff(t1, t2, ignore_order=True) >>> print (ddiff) {}

Lista que contiene diccionario:

>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}} >>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}} >>> ddiff = DeepDiff(t1, t2) >>> pprint (ddiff, indent = 2) { ''dic_item_removed'': ["root[4][''b''][2][2]"], ''values_changed'': {"root[4][''b''][2][1]": {''newvalue'': 3, ''oldvalue'': 1}}}

Conjuntos:

>>> t1 = {1, 2, 8} >>> t2 = {1, 2, 3, 5} >>> ddiff = DeepDiff(t1, t2) >>> pprint (DeepDiff(t1, t2)) {''set_item_added'': [''root[3]'', ''root[5]''], ''set_item_removed'': [''root[8]'']}

Nombrado Tuples:

>>> from collections import namedtuple >>> Point = namedtuple(''Point'', [''x'', ''y'']) >>> t1 = Point(x=11, y=22) >>> t2 = Point(x=11, y=23) >>> pprint (DeepDiff(t1, t2)) {''values_changed'': {''root.y'': {''newvalue'': 23, ''oldvalue'': 22}}}

Objetos personalizados:

>>> class ClassA(object): ... a = 1 ... def __init__(self, b): ... self.b = b ... >>> t1 = ClassA(1) >>> t2 = ClassA(2) >>> >>> pprint(DeepDiff(t1, t2)) {''values_changed'': {''root.b'': {''newvalue'': 2, ''oldvalue'': 1}}}

Atributo de objeto agregado:

>>> t2.c = "new attribute" >>> pprint(DeepDiff(t1, t2)) {''attribute_added'': [''root.c''], ''values_changed'': {''root.b'': {''newvalue'': 2, ''oldvalue'': 1}}}


Esta es una forma que funcionará, permite que las claves que evalúan False , y todavía utiliza una expresión de generador para caerse temprano si es posible. Aunque no es excepcionalmente bonito.

any(map(lambda x: True, (k for k in b if k not in a)))

EDITAR:

THC4k publicó una respuesta a mi comentario en otra respuesta. Aquí hay una manera mejor y más bonita de hacer lo anterior:

any(True for k in b if k not in a)

No estoy seguro de cómo eso nunca pasó por mi mente ...


Esta es una vieja pregunta y pregunta un poco menos de lo que necesitaba, por lo que esta respuesta realmente resuelve más de lo que esta pregunta me pide. Las respuestas en esta pregunta me ayudaron a resolver lo siguiente:

  1. (preguntado) Registre las diferencias entre dos diccionarios
  2. Combina las diferencias desde el # 1 al diccionario base
  3. (preguntado) Fusionar las diferencias entre dos diccionarios (tratar el diccionario n. ° 2 como si fuera un diccionario de diferencias)
  4. Intenta detectar los movimientos de los artículos y los cambios
  5. (preguntado) Haz todo esto recursivamente

Todo esto combinado con JSON brinda un soporte de almacenamiento de configuración bastante poderoso.

La solución ( también en github ):

from collections import OrderedDict from pprint import pprint class izipDestinationMatching(object): __slots__ = ("attr", "value", "index") def __init__(self, attr, value, index): self.attr, self.value, self.index = attr, value, index def __repr__(self): return "izip_destination_matching: found match by ''%s'' = ''%s'' @ %d" % (self.attr, self.value, self.index) def izip_destination(a, b, attrs, addMarker=True): """ Returns zipped lists, but final size is equal to b with (if shorter) a padded with nulls Additionally also tries to find item reallocations by searching child dicts (if they are dicts) for attribute, listed in attrs) When addMarker == False (patching), final size will be the longer of a, b """ for idx, item in enumerate(b): try: attr = next((x for x in attrs if x in item), None) # See if the item has any of the ID attributes match, matchIdx = next(((orgItm, idx) for idx, orgItm in enumerate(a) if attr in orgItm and orgItm[attr] == item[attr]), (None, None)) if attr else (None, None) if match and matchIdx != idx and addMarker: item[izipDestinationMatching] = izipDestinationMatching(attr, item[attr], matchIdx) except: match = None yield (match if match else a[idx] if len(a) > idx else None), item if not addMarker and len(a) > len(b): for item in a[len(b) - len(a):]: yield item, item def dictdiff(a, b, searchAttrs=[]): """ returns a dictionary which represents difference from a to b the return dict is as short as possible: equal items are removed added / changed items are listed removed items are listed with value=None Also processes list values where the resulting list size will match that of b. It can also search said list items (that are dicts) for identity values to detect changed positions. In case such identity value is found, it is kept so that it can be re-found during the merge phase @param a: original dict @param b: new dict @param searchAttrs: list of strings (keys to search for in sub-dicts) @return: dict / list / whatever input is """ if not (isinstance(a, dict) and isinstance(b, dict)): if isinstance(a, list) and isinstance(b, list): return [dictdiff(v1, v2, searchAttrs) for v1, v2 in izip_destination(a, b, searchAttrs)] return b res = OrderedDict() if izipDestinationMatching in b: keepKey = b[izipDestinationMatching].attr del b[izipDestinationMatching] else: keepKey = izipDestinationMatching for key in sorted(set(a.keys() + b.keys())): v1 = a.get(key, None) v2 = b.get(key, None) if keepKey == key or v1 != v2: res[key] = dictdiff(v1, v2, searchAttrs) if len(res) <= 1: res = dict(res) # This is only here for pretty print (OrderedDict doesn''t pprint nicely) return res def dictmerge(a, b, searchAttrs=[]): """ Returns a dictionary which merges differences recorded in b to base dictionary a Also processes list values where the resulting list size will match that of a It can also search said list items (that are dicts) for identity values to detect changed positions @param a: original dict @param b: diff dict to patch into a @param searchAttrs: list of strings (keys to search for in sub-dicts) @return: dict / list / whatever input is """ if not (isinstance(a, dict) and isinstance(b, dict)): if isinstance(a, list) and isinstance(b, list): return [dictmerge(v1, v2, searchAttrs) for v1, v2 in izip_destination(a, b, searchAttrs, False)] return b res = OrderedDict() for key in sorted(set(a.keys() + b.keys())): v1 = a.get(key, None) v2 = b.get(key, None) #print "processing", key, v1, v2, key not in b, dictmerge(v1, v2) if v2 is not None: res[key] = dictmerge(v1, v2, searchAttrs) elif key not in b: res[key] = v1 if len(res) <= 1: res = dict(res) # This is only here for pretty print (OrderedDict doesn''t pprint nicely) return res



Intenta esto para encontrar la intersección, las teclas que están en ambos dictionarie, si quieres las claves que no se encuentran en el segundo dictionarie, simplemente utiliza el no en ...

intersect = filter(lambda x, dictB=dictB.keys(): x in dictB, dictA.keys())


Mi receta de diferencia simétrica entre dos diccionarios:

def find_dict_diffs(dict1, dict2): unequal_keys = [] unequal_keys.extend(set(dict1.keys()).symmetric_difference(set(dict2.keys()))) for k in dict1.keys(): if dict1.get(k, ''N/A'') != dict2.get(k, ''N/A''): unequal_keys.append(k) if unequal_keys: print ''param'', ''dict1/t'', ''dict2'' for k in set(unequal_keys): print str(k)+''/t''+dict1.get(k, ''N/A'')+''/t ''+dict2.get(k, ''N/A'') else: print ''Dicts are equal'' dict1 = {1:''a'', 2:''b'', 3:''c'', 4:''d'', 5:''e''} dict2 = {1:''b'', 2:''a'', 3:''c'', 4:''d'', 6:''f''} find_dict_diffs(dict1, dict2)

Y el resultado es:

param dict1 dict2 1 a b 2 b a 5 e N/A 6 N/A f


No estoy seguro de si todavía es relevante pero me encontré con este problema, mi situación solo necesitaba devolver un diccionario de los cambios para todos los diccionarios anidados, etc. No pude encontrar una buena solución pero acabé escribiendo una función simple para hacer esto Espero que esto ayude,


Puede usar operaciones de conjunto en las teclas:

diff = set(dictb.keys()) - set(dicta.keys())

Aquí hay una clase para encontrar todas las posibilidades: qué se agregó, qué se eliminó, qué pares clave-valor son iguales y qué pares clave-valor se cambian.

class DictDiffer(object): """ Calculate the difference between two dictionaries as: (1) items added (2) items removed (3) keys same in both but changed values (4) keys same in both and unchanged values """ def __init__(self, current_dict, past_dict): self.current_dict, self.past_dict = current_dict, past_dict self.set_current, self.set_past = set(current_dict.keys()), set(past_dict.keys()) self.intersect = self.set_current.intersection(self.set_past) def added(self): return self.set_current - self.intersect def removed(self): return self.set_past - self.intersect def changed(self): return set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o]) def unchanged(self): return set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o])

Aquí hay algunos resultados de muestra:

>>> a = {''a'': 1, ''b'': 1, ''c'': 0} >>> b = {''a'': 1, ''b'': 2, ''d'': 0} >>> d = DictDiffer(b, a) >>> print "Added:", d.added() Added: set([''d'']) >>> print "Removed:", d.removed() Removed: set([''c'']) >>> print "Changed:", d.changed() Changed: set([''b'']) >>> print "Unchanged:", d.unchanged() Unchanged: set([''a''])

Disponible como repositorio de github: https://github.com/hughdbrown/dictdiffer


Si desea una solución integrada para una comparación completa con estructuras dict arbitrarias, la respuesta de @ Maxx es un buen comienzo.

import unittest test = unittest.TestCase() test.assertEqual(dictA, dictB)


Si está en Python ≥ 2.7:

# update different values in dictB # I would assume only dictA should be updated, # but the question specifies otherwise for k in dictA.viewkeys() & dictB.viewkeys(): if dictA[k] != dictB[k]: dictB[k]= dictA[k] # add missing keys to dictA dictA.update( (k,dictB[k]) for k in dictB.viewkeys() - dictA.viewkeys() )


Si realmente quiere decir exactamente lo que dice (que solo tiene que averiguar SI "hay claves" en B y no en A, NO QUÉ SIGNIFICAR), la forma más rápida debería ser:

if any(True for k in dictB if k not in dictA): ...

Si realmente necesita saber QUÉ CLAVES, si las hay, están en B y no en A, y no solo "SI" existen tales claves, entonces las respuestas existentes son bastante apropiadas (pero sí sugiero más precisión en preguntas futuras si eso es de hecho, lo que quieres decir ;-).


no estoy seguro si es "rápido" o no, pero normalmente, uno puede hacer esto

dicta = {"a":1,"b":2,"c":3,"d":4} dictb = {"a":1,"d":2} for key in dicta.keys(): if not key in dictb: print key


Use set() :

set(dictA.keys()).intersection(dictB.keys())