309 votes

Comparer deux dictionnaires et vérifier combien de paires (clé, valeur) sont égales.

J'ai deux dictionnaires, mais pour simplifier, je vais prendre ces deux-là :

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

Maintenant, je veux comparer si chaque key, value paire dans x a la même valeur correspondante dans y . Alors j'ai écrit ceci :

>>> 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

Et cela fonctionne depuis un tuple est retourné et ensuite comparé pour l'égalité.

Mes questions :

Est-ce correct ? Y a-t-il un meilleur manière de faire ça ? Mieux vaut ne pas parler de vitesse, je parle de l'élégance du code.

UPDATE : J'ai oublié de mentionner que je dois vérifier combien de key, value sont égales.

29 votes

x == y devrait être vrai selon stackoverflow.com/a/5635309/186202

1 votes

X == y devrait être vrai. On peut vérifier rapidement dans REPL. Veuillez vous référer : docs.python.org/2/library/stdtypes.html#mapping-types-dict

1 votes

x == y devrait être vrai selon le documentation officielle : " Les dictionnaires se comparent de manière égale si et seulement s'ils ont les mêmes paires (clé, valeur) (indépendamment de l'ordre). Les comparaisons dans l'ordre ('<', '<=', '>=', '>') génèrent une TypeError."

228voto

mouad Points 21520

Si vous voulez savoir combien de valeurs correspondent dans les deux dictionnaires, vous auriez dû le dire :)

Peut-être quelque chose comme ça :

shared_items = {k: x[k] for k in x if k in y and x[k] == y[k]}
print len(shared_items)

1 votes

Même erreur s'il y a un élément de liste pour la clé dict. Je pense que cmp est le meilleur moyen de le faire, à moins que je ne manque quelque chose.

1 votes

@Mutant c'est un problème différent. Vous ne pouvez pas créer un dictionnaire avec un list en premier lieu. x = {[1,2]: 2} échouera. La question est déjà valable dicts .

0 votes

@annan : faux, la question est générique. la exemple dans la description de la question a déjà des "dicts valides". Si je poste une nouvelle question, avec le même titre, mais avec une autre dictée "invalide", quelqu'un la marquera comme duplicata. Downvoting.

202voto

Jochen Ritzel Points 42916

Ce que vous voulez faire, c'est simplement x==y

Ce que vous faites n'est pas une bonne idée, car les éléments d'un dictionnaire ne sont pas censés avoir un ordre quelconque. Vous pourriez être en train de comparer [('a',1),('b',1)] avec [('b',1), ('a',1)] (mêmes dictionnaires, ordre différent).

Par exemple, voyez ceci :

>>> 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 différence n'est que d'un seul élément, mais votre algorithme verra que tous les articles sont différents

0 votes

@THC4k, désolé de ne pas l'avoir mentionné. Mais je dois vérifier combien de valeurs correspondent dans les deux dictionnaires.

0 votes

Ok, donc d'après ma mise à jour, ma façon de faire est-elle toujours incorrecte ?

0 votes

@A A : J'ai ajouté pourquoi le vôtre ne fonctionne pas quand vous voulez compter.

201voto

Daniel Points 21
def dict_compare(d1, d2):
    d1_keys = set(d1.keys())
    d2_keys = set(d2.keys())
    shared_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 shared_keys if d1[o] != d2[o]}
    same = set(o for o in shared_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)

10 votes

Celui-ci gère réellement les valeurs mutables dans le dict !

1 votes

Lorsque je l'exécute, j'obtiens toujours une erreur en traitant les valeurs mutables : ValueError : La valeur de vérité d'un DataFrame est ambiguë. Utilisez a.empty, a.bool(), a.item(), a.any() ou a.all().

3 votes

@Afflatus - DataFrame ne permettent pas les comparaisons véridiques (sauf si la longueur est égale à 1) car ils héritent de numpy.ndarray . -crédit à stackoverflow.com/a/33307396/994076

60voto

philipp Points 1327

Je suis novice en python mais j'ai fini par faire quelque chose de similaire à @mouad

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

L'opérateur XOR ( ^ ) devrait éliminer tous les éléments du dict lorsqu'ils sont les mêmes dans les deux dicts.

31 votes

Malheureusement, cela ne fonctionne pas si les valeurs du dict sont mutables (c'est-à-dire non hachables). (Ex {'a':{'b':1}} donne TypeError: unhashable type: 'dict' )

9voto

Alexander Points 332

La réponse de @mouad est intéressante si vous supposez que les deux dictionnaires ne contiennent que des valeurs simples. Cependant, si vous avez des dictionnaires qui contiennent des dictionnaires, vous obtiendrez une exception car les dictionnaires ne sont pas hachables.

En haut de ma tête, quelque chose comme ça pourrait marcher :

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(dict1.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

1 votes

Si vous utilisez not isinstance(dict1, dict) au lieu de type(dict1) is not dict cela fonctionnera sur d'autres classes basées sur dict. Also, instead of (dict1[clé] == dict2[clé]) , you can do all(atleast_1d(dict1[key] == dict2[key]))` pour gérer au moins les tableaux.

0 votes

+1, mais vous pourriez sortir de votre for loop dès que votre dicts_are_equal devient fausse. Il n'y a pas besoin de continuer plus loin.

0 votes

J'étais moi-même surpris mais il semble que je puisse comparer des dicts imbriquées avec == (en utilisant python3.8). >>> dict2 = {"a": {"a": {"a": "b"}}} >>> dict1 = {"a": {"a": {"a": "b"}}} >>> dict1 == dict2 True >>> dict1 = {"a": {"a": {"a": "a"}}} >>> dict1 == dict2 False

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X