15 votes

python : trouver seulement les paires clé-valeur communes de plusieurs dicts : dict intersection

J'ai 0 ou plusieurs dicts dans une liste :

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

Je souhaite créer un nouveau dict qui ne contienne que les clés qui se trouvent dans tous les dicts ci-dessus, et seulement si les valeurs sont toutes identiques :

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

Je pense qu'il devrait y avoir un élégant manière d'écrire dict_intersection mais je ne trouve que des solutions inélégantes et/ou inefficaces. Des suggestions ?

23voto

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

Remarque : cette solution exige que les valeurs du dictionnaire soient hachables, en plus des clés.

5voto

Johannes Charra Points 6720

Puisque les paires clé/valeur doivent déjà se trouver dans le premier dict, vous pouvez itérer sur les éléments de ce dict.

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

Cette solution est moins élégante que celle d'interjay, mais elle fonctionne sans la restriction des valeurs hachables.

Edit : Changer le all expression vers une expression de générateur pour améliorer la vitesse

4voto

Li-aung Yip Points 7209

Qu'en est-il ?

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

Modifier(1) : Je ne sais pas lequel des deux est le plus rapide. Les set.intersection sont certainement les plus élégantes ( court ), mais je serais intéressé par une analyse comparative.

Modifier(2) : Bonus - obtenir toutes les entrées du dictionnaire dont les paires (clé:valeur) sont communes à deux dictionnaires :

{k:count for k,count in
 collections.Counter(itertools.chain(*[d.iteritems() for d in dicts])).iteritems()
 if count > 1}

3voto

jamylak Points 38094
>>> 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}

1voto

Scott Hunter Points 10356

Une approche un peu plus pratique : Prenez la liste des clés de chaque dictionnaire, triez chaque liste, puis procédez comme si vous les fusionniez (gardez un index pour chaque liste, avancez celle qui a la valeur la plus basse). Lorsque tous les indices pointent vers la même clé, vérifiez l'égalité des valeurs ; dans tous les cas, avancez tous les indices.

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