How to merge dictionaries of dictionaries?

后端 未结 29 2770
渐次进展
渐次进展 2020-11-22 05:13

I need to merge multiple dictionaries, here\'s what I have for instance:

dict1 = {1:{\"a\":{A}}, 2:{\"b\":{B}}}

dict2 = {2:{\"c\":{C}}, 3:{\"d\":{D}}


        
相关标签:
29条回答
  • 2020-11-22 06:14

    I had two dictionaries (a and b) which could each contain any number of nested dictionaries. I wanted to recursively merge them, with b taking precedence over a.

    Considering the nested dictionaries as trees, what I wanted was:

    • To update a so that every path to every leaf in b would be represented in a
    • To overwrite subtrees of a if a leaf is found in the corresponding path in b
      • Maintain the invariant that all b leaf nodes remain leafs.

    The existing answers were a little complicated for my taste and left some details on the shelf. I hacked together the following, which passes unit tests for my data set.

      def merge_map(a, b):
        if not isinstance(a, dict) or not isinstance(b, dict):
          return b
    
        for key in b.keys():
          a[key] = merge_map(a[key], b[key]) if key in a else b[key]
        return a
    

    Example (formatted for clarity):

     a = {
        1 : {'a': 'red', 
             'b': {'blue': 'fish', 'yellow': 'bear' },
             'c': { 'orange': 'dog'},
        },
        2 : {'d': 'green'},
        3: 'e'
      }
    
      b = {
        1 : {'b': 'white'},
        2 : {'d': 'black'},
        3: 'e'
      }
    
    
      >>> merge_map(a, b)
      {1: {'a': 'red', 
           'b': 'white',
           'c': {'orange': 'dog'},},
       2: {'d': 'black'},
       3: 'e'}
    

    The paths in b that needed to be maintained were:

    • 1 -> 'b' -> 'white'
    • 2 -> 'd' -> 'black'
    • 3 -> 'e'.

    a had the unique and non-conflicting paths of:

    • 1 -> 'a' -> 'red'
    • 1 -> 'c' -> 'orange' -> 'dog'

    so they are still represented in the merged map.

    0 讨论(0)
  • 2020-11-22 06:15

    This simple recursive procedure will merge one dictionary into another while overriding conflicting keys:

    #!/usr/bin/env python2.7
    
    def merge_dicts(dict1, dict2):
        """ Recursively merges dict2 into dict1 """
        if not isinstance(dict1, dict) or not isinstance(dict2, dict):
            return dict2
        for k in dict2:
            if k in dict1:
                dict1[k] = merge_dicts(dict1[k], dict2[k])
            else:
                dict1[k] = dict2[k]
        return dict1
    
    print (merge_dicts({1:{"a":"A"}, 2:{"b":"B"}}, {2:{"c":"C"}, 3:{"d":"D"}}))
    print (merge_dicts({1:{"a":"A"}, 2:{"b":"B"}}, {1:{"a":"A"}, 2:{"b":"C"}}))
    

    Output:

    {1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}}
    {1: {'a': 'A'}, 2: {'b': 'C'}}
    
    0 讨论(0)
  • 2020-11-22 06:15

    If you have an unknown level of dictionaries, then I would suggest a recursive function:

    def combineDicts(dictionary1, dictionary2):
        output = {}
        for item, value in dictionary1.iteritems():
            if dictionary2.has_key(item):
                if isinstance(dictionary2[item], dict):
                    output[item] = combineDicts(value, dictionary2.pop(item))
            else:
                output[item] = value
        for item, value in dictionary2.iteritems():
             output[item] = value
        return output
    
    0 讨论(0)
  • 2020-11-22 06:15

    Easiest way i can think of is :

    #!/usr/bin/python
    
    from copy import deepcopy
    def dict_merge(a, b):
        if not isinstance(b, dict):
            return b
        result = deepcopy(a)
        for k, v in b.iteritems():
            if k in result and isinstance(result[k], dict):
                    result[k] = dict_merge(result[k], v)
            else:
                result[k] = deepcopy(v)
        return result
    
    a = {1:{"a":'A'}, 2:{"b":'B'}}
    b = {2:{"c":'C'}, 3:{"d":'D'}}
    
    print dict_merge(a,b)
    

    Output:

    {1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}}
    
    0 讨论(0)
  • 2020-11-22 06:19

    And just another slight variation:

    Here is a pure python3 set based deep update function. It updates nested dictionaries by looping through one level at a time and calls itself to update each next level of dictionary values:

    def deep_update(dict_original, dict_update):
        if isinstance(dict_original, dict) and isinstance(dict_update, dict):
            output=dict(dict_original)
            keys_original=set(dict_original.keys())
            keys_update=set(dict_update.keys())
            similar_keys=keys_original.intersection(keys_update)
            similar_dict={key:deep_update(dict_original[key], dict_update[key]) for key in similar_keys}
            new_keys=keys_update.difference(keys_original)
            new_dict={key:dict_update[key] for key in new_keys}
            output.update(similar_dict)
            output.update(new_dict)
            return output
        else:
            return dict_update
    

    A simple example:

    x={'a':{'b':{'c':1, 'd':1}}}
    y={'a':{'b':{'d':2, 'e':2}}, 'f':2}
    
    print(deep_update(x, y))
    >>> {'a': {'b': {'c': 1, 'd': 2, 'e': 2}}, 'f': 2}
    
    0 讨论(0)
提交回复
热议问题