Je cherche un moyen de déterminer la différence de n dictionnaires dans le scénario suivant: Il existe n dictionnaires. Certaines de leurs clés correspondent, mais pas toutes. Comme ça:

dict_a = {
    'keyA': 'valueA',
    'keyB': 'valueB',
    'keyC': 'valueC',
    'keyD': 'valueD',
    'keyE': 'valueE',
    'keyF': 'valueF',
    'keyG': 'valueG'
}
dict_b = {
    'keyA': 'valueA',
    'keyB': 'valueB',
    'keyX': 'valueX',
    'keyD': 'valueH',
    'keyE': 'valueE',
    'keyF': 'valueF',
    'keyG': 'valueG'
}

Je veux pouvoir dire si la valeur d'une clé est différente de la valeur de la même clé dans un autre dictionnaire. Dans l'exemple ci-dessus, keyD doit être renvoyé, car sa valeur est différente dans dict_a et dict_b. keyX ne doit pas être renvoyé, car il ne se produit que dans dict_b. C'est relativement facile avec seulement deux dictionnaires, mais quelle est la meilleure pratique pour y parvenir avec les dictionnaires n?

0
0x6470 2 juin 2020 à 20:36

3 réponses

Meilleure réponse

Parcourez la liste des dictionnaires à comparer et gardez une trace de toutes les clés que vous avez vues précédemment et de leurs valeurs (effectuées via l'appel orig.update()).

compare = [{
    'keyA': 'valueA',
    'keyB': 'valueB',
    'keyC': 'valueC',
    'keyD': 'valueD',
    'keyE': 'valueE',
    'keyF': 'valueF',
    'keyG': 'valueG'
},
{
    'keyA': 'valueA',
    'keyB': 'valueB',
    'keyX': 'valueX',
    'keyD': 'valueH',
    'keyE': 'valueE',
    'keyF': 'valueF',
    'keyG': 'valueG'
},
{
    'keyA': 'valueA',
    'keyB': 'valueB',
    'keyX': 'valueX',
    'keyD': 'valueH',
    'keyE': 'valueE',
    'keyF': 'valueF',
    'keyG': 'valueB'
}]

orig = compare[0]
diffs = []

for comp in compare[1:]:
    for k in comp:
        if k in orig and orig[k] != comp[k]:
            diffs.append(k)

    orig.update(comp)

print(diffs)

.. renvoie ['keyD', 'keyG'] qui sont les deux clés qui ont des valeurs différentes des trois dicts. Remplacez diffs par un dictionnaire et utilisez dict.values() si vous ne voulez pas que les clés apparaissent plusieurs fois (c'est-à-dire si vous avez seulement besoin de savoir qu'elles ont changé, pas combien de fois elles ont changé ).

0
MatsLindh 2 juin 2020 à 17:59

Vous pouvez créer cette simple fonction lambda pour ce faire:

>>> diff_keys = lambda x,y: [key for key in x.keys() if key in y.keys() and x[key] != y[key]]

>>> diff_keys(dict_a, dict_b)
['keyD']

Et pour gérer n autres dictionnaires, vous pouvez créer une autre fonction qui peut le faire comme celle-ci:

>>> def get_different_keys(original_dict: dict, other_dicts: list):
...     different_keys = []
...     for dict_x in other_dicts:
...         different_keys.extend(diff_keys(original_dict, dict_x))
...         original_dict.update(dict_x)
...     return different_keys

>>> get_different_keys(dict_a, [dict_b]))
['keyD']
0
Anwarvic 2 juin 2020 à 18:31
dict_a = {
    'keyA': 'valueA',
    'keyB': 'valueB',
    'keyC': 'valueC',
    'keyD': 'valueD',
    'keyE': 'valueE',
    'keyF': 'valueF',
    'keyG': 'valueG'
}

dict_b = {
    'keyA': 'valueA',
    'keyB': 'valueB',
    'keyX': 'valueX',
    'keyD': 'valueH',
    'keyE': 'valueE',
    'keyF': 'valueF',
    'keyG': 'valueG'
}

dict_c = {
    'keyA': 'valueA',
    'keyB': 'valueB',
    'keyX': 'valueX',
    'keyD': 'valueH',
    'keyE': 'valueO',    # <- here is additional difference
    'keyF': 'valueF',
    'keyG': 'valueG'
}

# Step 1: prepare list of all dict

dicts = [dict_a, dict_b, dict_c]

# Step 2: get all common keys 

ks = [set(i.keys()) for i in dicts]
ks_i = list(ks[0].intersection(*ks[1:]))
ks_i

Out[1]:  # here is the list of common keys
['keyB', 'keyE', 'keyF', 'keyD', 'keyG', 'keyA']

# Step 3: get set of values taken from the different dict by the same keys

unequal = [{i[k] for i in dicts} for k in ks_i]
unequal
Out[2]:                 #show set of values for same keys  
[{'valueB'},            # for keyB
 {'valueE', 'valueO'},  # for keyE
 {'valueF'},            # and so on
 {'valueD', 'valueH'},
 {'valueG'},
 {'valueA'}]


# Step 4: check if the length of set and chooe appropriate keys
# if the set has length >1 then it has different values inside

[ks_i[ind] for ind,v in enumerate(unequal) if len(v) >1]

Out[3]:
['keyE', 'keyD']
0
Alexey 2 juin 2020 à 18:17