valor recorrer elementos ejemplo diccionario dentro buscar agregar python dictionary comparison

recorrer - diccionario python ejemplo



Comparando dos diccionarios en Python (16)

Código

def equal(a, b): type_a = type(a) type_b = type(b) if type_a != type_b: return False if isinstance(a, dict): if len(a) != len(b): return False for key in a: if key not in b: return False if not equal(a[key], b[key]): return False return True elif isinstance(a, list): if len(a) != len(b): return False while len(a): x = a.pop() index = indexof(x, b) if index == -1: return False del b[index] return True else: return a == b def indexof(x, a): for i in range(len(a)): if equal(x, a[i]): return i return -1

Prueba

>>> a = { ''number'': 1, ''list'': [''one'', ''two''] } >>> b = { ''list'': [''two'', ''one''], ''number'': 1 } >>> equal(a, b) True

Tengo dos diccionarios, pero para simplificar, tomaré estos dos:

>>> x = dict(a=1, b=2) >>> y = dict(a=2, b=2)

Ahora, quiero comparar si cada key, value par de key, value en x tiene el mismo valor correspondiente en y . Entonces escribí esto:

>>> for x_values, y_values in zip(x.iteritems(), y.iteritems()): if x_values == y_values: print ''Ok'', x_values, y_values else: print ''Not'', x_values, y_values

Y funciona desde que se devuelve una tuple y luego se compara por igualdad.

Mis preguntas:

¿Es esto correcto? ¿Hay una mejor manera de hacer esto? Mejor no en velocidad, estoy hablando de elegancia de código.

ACTUALIZACIÓN: Olvidé mencionar que tengo que verificar cuántos pares key, value son iguales.


En PyUnit hay un método que compara bellamente los diccionarios. Lo probé usando los dos diccionarios siguientes y hace exactamente lo que estás buscando.

d1 = {1: "value1", 2: [{"subKey1":"subValue1", "subKey2":"subValue2"}]} d2 = {1: "value1", 2: [{"subKey2":"subValue2", "subKey1": "subValue1"}] } def assertDictEqual(self, d1, d2, msg=None): self.assertIsInstance(d1, dict, ''First argument is not a dictionary'') self.assertIsInstance(d2, dict, ''Second argument is not a dictionary'') if d1 != d2: standardMsg = ''%s != %s'' % (safe_repr(d1, True), safe_repr(d2, True)) diff = (''/n'' + ''/n''.join(difflib.ndiff( pprint.pformat(d1).splitlines(), pprint.pformat(d2).splitlines()))) standardMsg = self._truncateMessage(standardMsg, diff) self.fail(self._formatMessage(msg, standardMsg))

No recomiendo importar unittest en tu código de producción. Mi pensamiento es que la fuente en PyUnit podría ser rediseñada para ejecutarse en producción. Utiliza pprint que "imprime bastante" los diccionarios. Parece bastante fácil adaptar este código para que esté "listo para producción".


En Python 3.6, se puede hacer como: -

if (len(dict_1)==len(dict_2): for i in dict_1.items(): ret=bool(i in dict_2.items())

La variable ret será verdadera si todos los elementos de dict_1 están presentes en dict_2


La función es buena IMO, clara e intuitiva. Pero solo para darle (otra) respuesta, aquí está mi respuesta:

def compare_dict(dict1, dict2): for x1 in dict1.keys(): z = dict1.get(x1) == dict2.get(x1) if not z: print(''key'', x1) print(''value A'', dict1.get(x1), ''/nvalue B'', dict2.get(x1)) print(''-----/n'')

Puede ser útil para usted o para cualquier otra persona ..


La respuesta de @mouad es agradable si se supone que ambos diccionarios solo contienen valores simples. Sin embargo, si tiene diccionarios que contienen diccionarios, obtendrá una excepción ya que los diccionarios no son aptos para el uso.

Por la parte superior de mi cabeza, algo como esto podría funcionar:

def compare_dictionaries(dict1, dict2): if dict1 is None or dict2 is None: print(''Nones'') return False if (not isinstance(dict1, dict)) or (not isinstance(dict2, dict)): print(''Not dict'') return False shared_keys = set(dict2.keys()) & set(dict2.keys()) if not ( len(shared_keys) == len(dict1.keys()) and len(shared_keys) == len(dict2.keys())): print(''Not all keys are shared'') return False dicts_are_equal = True for key in dict1.keys(): if isinstance(dict1[key], dict) or isinstance(dict2[key], dict): dicts_are_equal = dicts_are_equal and compare_dictionaries(dict1[key], dict2[key]) else: dicts_are_equal = dicts_are_equal and all(atleast_1d(dict1[key] == dict2[key])) return dicts_are_equal

Tenga en cuenta que todavía no estoy contento con la línea:

dicts_are_equal = dicts_are_equal and (dict1[key] == dict2[key])

como los valores de estos podrían ser objetos. Sería bueno poder verificar si los dos objetos estaban implementando una interfaz comparable.


Lo que quieres hacer es simplemente x==y

Lo que hagas no es una buena idea, porque se supone que los elementos en un diccionario no tienen ningún orden. Usted podría estar comparando [(''a'',1),(''b'',1)] con [(''b'',1), (''a'',1)] (mismos diccionarios, diferente orden).

Por ejemplo, mira esto:

>>> x = dict(a=2, b=2,c=3, d=4) >>> x {''a'': 2, ''c'': 3, ''b'': 2, ''d'': 4} >>> y = dict(b=2,c=3, d=4) >>> y {''c'': 3, ''b'': 2, ''d'': 4} >>> zip(x.iteritems(), y.iteritems()) [((''a'', 2), (''c'', 3)), ((''c'', 3), (''b'', 2)), ((''b'', 2), (''d'', 4))]

La diferencia es solo un elemento, pero su algoritmo verá que todos los elementos son diferentes


Otra posibilidad más, hasta la última nota del OP, es comparar los hash ( SHA o MD ) de los dicts arrojados como JSON. La forma en que se construyen los valores hash garantiza que, si son iguales, las cadenas fuente son iguales también. Esto es muy rápido y matemáticamente sano.

import json import hashlib def hash_dict(d): return hashlib.sha1(json.dumps(d, sort_keys=True)).hexdigest() x = dict(a=1, b=2) y = dict(a=2, b=2) z = dict(a=1, b=2) print(hash_dict(x) == hash_dict(y)) print(hash_dict(x) == hash_dict(z))


Para probar si dos dicts son iguales en claves y valores:

def dicts_equal(d1,d2): """ return True if all keys and values are the same """ return all(k in d2 and d1[k] == d2[k] for k in d1) / and all(k in d1 and d1[k] == d2[k] for k in d2)

Si desea devolver los valores que difieren, escríbalo de manera diferente:

def dict1_minus_d2(d1, d2): """ return the subset of d1 where the keys don''t exist in d2 or the values in d2 are different, as a dict """ return {k,v for k,v in d1.items() if k in d2 and v == d2[k]}

Deberías llamarlo dos veces, es decir,

dict1_minus_d2(d1,d2).extend(dict1_minus_d2(d2,d1))


Para verificar si dos diccionarios tienen el mismo contenido, use:

dic1 == dic2

De los documentos de Python :

Para ilustrar, los siguientes ejemplos devuelven un diccionario igual a {"one": 1, "two": 2, "three": 3} :

>>> a = dict(one=1, two=2, three=3) >>> b = {''one'': 1, ''two'': 2, ''three'': 3} >>> c = dict(zip([''one'', ''two'', ''three''], [1, 2, 3])) >>> d = dict([(''two'', 2), (''one'', 1), (''three'', 3)]) >>> e = dict({''three'': 3, ''one'': 1, ''two'': 2}) >>> a == b == c == d == e True


Si quieres saber cuántos valores coinciden en ambos diccionarios, deberías haber dicho eso :)

Tal vez algo como esto:

shared_items = set(x.items()) & set(y.items()) print len(shared_items)


Solo usa:

assert cmp(dict1, dict2) == 0


Soy nuevo en Python pero terminé haciendo algo similar a @mouad

unmatched_item = set(dict_1.items()) ^ set(dict_2.items()) len(unmatched_item) # should be 0

El operador XOR ( ^ ) debería eliminar todos los elementos del dict cuando son iguales en ambos dicts.


ver objetos de vista de diccionario: https://docs.python.org/2/library/stdtypes.html#dict

De esta forma, puede restar dictView2 de dictView1 y devolverá un conjunto de pares clave / valor que son diferentes en dictView2:

original = {''one'':1,''two'':2,''ACTION'':''ADD''} originalView=original.viewitems() updatedDict = {''one'':1,''two'':2,''ACTION'':''REPLACE''} updatedDictView=updatedDict.viewitems() delta=original | updatedDict print delta >>set([(''ACTION'', ''REPLACE'')])

Puede intersecar, unir, diferenciar (se muestra arriba), diferencia simétrica estos objetos de vista de diccionario.
¿Mejor? ¿Más rápido? - no estoy seguro, pero es parte de la biblioteca estándar, lo que lo convierte en una gran ventaja para la portabilidad


>>> hash_1 {''a'': ''foo'', ''b'': ''bar''} >>> hash_2 {''a'': ''foo'', ''b'': ''bar''} >>> set_1 = set (hash_1.iteritems()) >>> set_1 set([(''a'', ''foo''), (''b'', ''bar'')]) >>> set_2 = set (hash_2.iteritems()) >>> set_2 set([(''a'', ''foo''), (''b'', ''bar'')]) >>> len (set_1.difference(set_2)) 0 >>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False: ... print "The two hashes match." ... The two hashes match. >>> hash_2[''c''] = ''baz'' >>> hash_2 {''a'': ''foo'', ''c'': ''baz'', ''b'': ''bar''} >>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False: ... print "The two hashes match." ... >>> >>> hash_2.pop(''c'') ''baz''

Aquí hay otra opción:

>>> id(hash_1) 140640738806240 >>> id(hash_2) 140640738994848

Entonces, como ves, las dos identificaciones son diferentes. Pero los operadores de comparación ricos parecen hacer el truco:

>>> hash_1 == hash_2 True >>> >>> hash_2 {''a'': ''foo'', ''b'': ''bar''} >>> set_2 = set (hash_2.iteritems()) >>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False: ... print "The two hashes match." ... The two hashes match. >>>


def dict_compare(d1, d2): d1_keys = set(d1.keys()) d2_keys = set(d2.keys()) intersect_keys = d1_keys.intersection(d2_keys) added = d1_keys - d2_keys removed = d2_keys - d1_keys modified = {o : (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]} same = set(o for o in intersect_keys if d1[o] == d2[o]) return added, removed, modified, same x = dict(a=1, b=2) y = dict(a=2, b=2) added, removed, modified, same = dict_compare(x, y)


import json if json.dumps(dict1) == json.dumps(dict2): print("Equal")