110 votes

Comment fusionner et sommer deux dictionnaires en Python?

J'ai un dictionnaire ci-dessous, et je veux ajouter à un autre dictionnaire avec des éléments non nécessairement distincts et fusionner ses résultats.

Y a-t-il une fonction intégrée pour cela, ou dois-je créer la mienne?

{
  '6d6e7bf221ae24e07ab90bba4452267b05db7824cd3fd1ea94b2c9a8': 6,
  '7c4a462a6ed4a3070b6d78d97c90ac230330603d24a58cafa79caf42': 7,
  '9c37bdc9f4750dd7ee2b558d6c06400c921f4d74aabd02ed5b4ddb38': 9,
  'd3abb28d5776aef6b728920b5d7ff86fa3a71521a06538d2ad59375a': 15,
  '2ca9e1f9cbcd76a5ce1772f9b59995fd32cbcffa8a3b01b5c9c8afc2': 11
}

Le nombre d'éléments dans le dictionnaire est également inconnu.

Lors de la fusion, si deux clés identiques sont rencontrées, les valeurs de ces clés doivent être additionnées au lieu d'être écrasées.

2voto

renskiy Points 828
d1 = {'pommes': 2, 'banane': 1}
d2 = {'pommes': 3, 'banane': 2}
fusionné = reduce(
    lambda d, i: (
        d.update(((i[0], d.get(i[0], 0) + i[1]),)) or d
    ),
    d2.iteritems(),
    d1.copy(),
)

Il y a aussi un remplacement assez simple de dict.update():

fusionné = dict(d1, **d2)

2voto

John Mutuma Points 378
class dict_merge(dict):
def __add__(self, other):
    result = dict_merge({})
    for key in self.keys():
        if key in other.keys():
            result[key] = self[key] + other[key]
        else:
            result[key] = self[key]
    for key in other.keys():
        if key in self.keys():
            pass
        else:
            result[key] = other[key]
    return result

a = dict_merge({"a":2, "b":3, "d":4})
b = dict_merge({"a":1, "b":2})
c = dict_merge({"a":5, "b":6, "c":5})
d = dict_merge({"a":8, "b":6, "e":5})

print((a + b + c +d))

>>> {'a': 16, 'b': 17, 'd': 4, 'c': 5, 'e': 5}

C'est une surcharge d'opérateur. En utilisant __add__, nous avons défini comment utiliser l'opérateur + pour notre dict_merge qui hérite du dict python intégré. Vous pouvez continuer et le rendre plus flexible en utilisant une méthode similaire pour définir d'autres opérateurs dans la même classe par exemple * avec __mul__ pour la multiplication, ou / avec __div__ pour la division, ou même % avec __mod__ pour le modulo, en remplaçant le + dans self[key] + other[key] par l'opérateur correspondant, si jamais vous avez besoin d'une telle fusion. Je n'ai testé que comme il est sans autres opérateurs, mais je ne prévois pas de problème avec d'autres opérateurs. Apprenez simplement en essayant.

0voto

Aidan Farhi Points 1

Une approche assez simple:

from collections import Counter
from functools import reduce

data = [
  {'x': 10, 'y': 1, 'z': 100},
  {'x': 20, 'y': 2, 'z': 200},
  {'a': 10, 'z': 300}
]

result = dict(reduce(lambda x, y: Counter(x) + Counter(y), data))

0voto

Memin Points 1

TL;DR;

Ce code fonctionne à la fois pour la liste de dictionnaires et pour la série pandas (lorsque les dictionnaires sont des éléments de lignes). Il est super rapide.


La méthode @Havok est de loin la meilleure méthode selon mes tests, et comme d'autres tests le confirment également, je ne vais pas mettre les résultats des tests ici, mais au lieu de cela, je partage mon code en plus de la méthode d'Havok. Donc, le code suivant fonctionne pour une liste de dictionnaires et également pour la série pandas où chaque ligne contient un dictionnaire.

from functools import reduce
def reducer(accumulateur, element):
    """Les clés de deux dictionnaires sont unies, et leurs valeurs sont additionnées si les clés sont identiques,
    voir explication ici https://stackoverflow.com/a/46128481/2234161"""
    for cle, valeur in element.items():
        if accumulateur.get(cle, 0)!=0 and not accumulateur.get(cle, 0):
            print("pourquoi pas", accumulateur.get(cle, 0))
        elif not valeur:
            print("pourquoi pas de valeur", valeur)
        accumulateur[cle] = accumulateur.get(cle, 0) + valeur
    return accumulateur

def somme_dicts(collection_dicts, dict_initial = None):
    """
    Pour une collection de dictionnaires donnée, elle additionne les valeurs des clés identiques
    :param collection_dicts: [liste de dictionnaires, cela peut être une série pandas où chaque colonne a un dictionnaire]
    :param dict_initial: [s'il y a un dictionnaire initial sur lequel la collection_dicts sera ajoutée], par défaut dict()
    """
    res=None
    if not dict_initial:
        dict_initial = dict()
    try:
        res = reduce(reducer, collection_dicts, dict_initial)
    except Exception as ex:
        print(f"Erreur lors de la réduction du dictionnaire : {collection_dicts}", ex)
        raise ex
    return res

dict_resultat = somme_dicts(liste_de_dictionnaires_ou_serie_pandas)

0voto

Dima Points 1

Créez deux dictionnaires avec des valeurs entières aléatoires

plusieurs colonnes ont les mêmes noms
import random
import pandas as pd

def create_random_dict(txt):
    my_dict = {}
    for c in txt:
        my_dict[c] = random.randint(1,30219)
    return my_dict

dict1 = create_random_dict('abcdefg')
dict2 = create_random_dict('cxzdywuf')
print(dict1)
print(dict2)
vos résultats d'impression peuvent différer en raison de la randomisation

{'a': 21804, 'b': 19749, 'c': 16837, 'd': 10134, 'e': 26181, 'f': 8343, 'g': 10268}
{'z': 12763, 'x': 23583, 'c': 20710, 'd': 22395, 'y': 25782, 'f': 23376, 'w': 25857, 'u': 9154}

Collectez toutes les clés des deux dictionnaires

cols = list(dict1.keys())+list(dict2.keys())

Supprimez les doublons des noms de colonnes

cols = list(dict.fromkeys(cols))

Créez des dataframes correspondant aux dictionnaires

df1 = pd.DataFrame(dict1, columns=cols, index=[0]).fillna(0)
df2 = pd.DataFrame(dict2, columns=cols, index=[0]).fillna(0)

additionnez les dataframes et transformez-les à nouveau en dictionnaire

résultat = (df1+df2).T.to_dict()[0]
print(result)

{'a': 21804, 'b': 19749, 'c': 37547, 'd': 32529, 'e': 26181, 'f': 31719, 'g': 10268, 'z': 12763, 'x': 23583, 'y': 25782, 'w': 25857, 'u': 9154}

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