2011-06-06 4 views
1

Y at-il un moyen facile de combiner deux dictionnaires de dictionnaires en Python? Voici ce que j'ai besoin:Combiner deux dictionnaires de dictionnaires (Python)

dict1 = {'A' : {'B' : 'C'}} 
dict2 = {'A' : {'D' : 'E'}} 

result = dict_union(dict1, dict2) 
# => result = {'A' : {'B' : 'C', 'D' : 'E'}} 

J'ai créé une fonction de force brute qu'il fait, mais je cherchais une solution plus compacte:

def dict_union(train, wagon): 
    for key, val in wagon.iteritems(): 
     if not isinstance(val, dict): 
      train[key] = val 
     else: 
      subdict = train.setdefault(key, {}) 
      dict_union(subdict, val) 
+5

Ce n'est pas une union 'dict'. –

+4

Je ne comprends pas ce que vous voulez faire quand la structure des dicts ne correspond pas. Par exemple, si dict3 = {'A': 'F'}, alors en utilisant votre version ici, dict_union (dict3, dict2) lance un TypeError. Est-ce le comportement souhaité? – Cosmologicon

+0

Relié (mais plus simple): http://stackoverflow.com/questions/1031199/adding-dictionaries-in-python – Gilles

Répondre

0

Vous pouvez sous-classe dict et envelopper la méthode dict.update() originale avec une version qui appellerait update() sur les subdicts plutôt que d'écraser directement les sous-titres. Cela peut prendre au moins autant d'efforts que votre solution existante, cependant.

+0

Oui, mais vous devez vous assurer que tous les dicts dans les dicts qui sont mis à jour sont également des exemples de votre sous-classe. – Cosmologicon

0

Doit être récursif, car les dictionnaires peuvent être imbriqués. Voici mon premier point de vue, vous voudrez probablement définir votre comportement lorsque les dictionnaires nichent à différentes profondeurs.

def join(A, B): 
    if not isinstance(A, dict) or not isinstance(B, dict): 
     return A or B 
    return dict([(a, join(A.get(a), B.get(a))) for a in set(A.keys()) | set(B.keys())]) 

def main(): 
    A = {'A': {'B': 'C'}, 'D': {'X': 'Y'}} 
    B = {'A': {'D': 'E'}} 
    print join(A, B) 
+0

Cela renvoie un résultat différent de la fonction OP pour les arguments {'A': {'B': 'C'}} et {'A': 'F'}. Cependant, je ne suis pas sûr que l'OP ait pensé à cet exemple. – Cosmologicon

+1

Ouais tu as raison, c'est ce que j'ai dit sur le comportement quand les dicts ont des profondeurs différentes. Vous devez définir votre propre. Je viens de renvoyer le premier qui est non Aucun 'A ou B'. Vous pouvez faire 'B ou A', ce que fait son code, ou toute autre résolution de conflit. –

3

Cette solution est plutôt compacte. Il est laid, mais vous demandez à un comportement assez compliqué:

dict_union = lambda d1,d2: dict((x,(dict_union(d1.get(x,{}),d2[x]) if 
    isinstance(d2.get(x),dict) else d2.get(x,d1.get(x)))) for x in 
    set(d1.keys()+d2.keys())) 
0

Quant à moi il n'y a pas d'information enaugh mais de toute façon s'il vous plaît trouver mon code exemple ci-dessous:

dict1 = {'A' : {'B' : 'C'}} 
dict2 = {'A' : {'D' : 'E'}, 'B':{'C':'D'}} 
output = {} 
for key in (set(dict1) | set(dict2): 
    output[key] = {} 
    (key in dict1 and output[key].update(dict1.get(key))) 
    (key in dict2 and output[key].update(dict2.get(key))) 
4

est ici une classe, RUDict (pour Recursive-Update dict) qui implémente le comportement que vous recherchez:

class RUDict(dict): 

    def __init__(self, *args, **kw): 
     super(RUDict,self).__init__(*args, **kw) 

    def update(self, E=None, **F): 
     if E is not None: 
      if 'keys' in dir(E) and callable(getattr(E, 'keys')): 
       for k in E: 
        if k in self: # existing ...must recurse into both sides 
         self.r_update(k, E) 
        else: # doesn't currently exist, just update 
         self[k] = E[k] 
      else: 
       for (k, v) in E: 
        self.r_update(k, {k:v}) 

     for k in F: 
      self.r_update(k, {k:F[k]}) 

    def r_update(self, key, other_dict): 
     if isinstance(self[key], dict) and isinstance(other_dict[key], dict): 
      od = RUDict(self[key]) 
      nd = other_dict[key] 
      od.update(nd) 
      self[key] = od 
     else: 
      self[key] = other_dict[key] 


def test(): 
    dict1 = {'A' : {'B' : 'C'}} 
    dict2 = {'A' : {'D' : 'E'}} 

    dx = RUDict(dict1) 
    dx.update(dict2) 
    print(dx) 


if __name__ == '__main__': 
    test() 


>>> import RUDict 
>>> RUDict.test() 
{'A': {'B': 'C', 'D': 'E'}} 
>>>