Take the 2-minute tour ×

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

with A B C and D being leaves of the tree, like {"info1":"value", "info2":"value2"}

There is an unknown level(depth) of dictionaries, it could be {2:{"c":{"z":{"y":{C}}}}}

In my case it represents a directory/files structure with nodes being docs and leaves being files.

I want to merge them to obtain dict3={1:{"a":{A}},2:{"b":{B},"c":{C}},3:{"d":{D}}}

I'm not sure how I could do that easily with Python, if anyone could help, thanks!


share|improve this question
What do you want for your arbitrary depth of dictionaries? Do you want y flattened up to the c level or what? Your example is incomplete. –  agf Aug 26 '11 at 13:14
Check my NestedDict class here: stackoverflow.com/a/16296144/2334951 It does managing of nested dictionary structures like merging & more. –  SzieberthAdam May 5 '13 at 13:45
add comment

9 Answers

up vote 14 down vote accepted

this is actually quite tricky - particularly if you want a useful error message when things are inconsistent, while correctly accepting duplicate but consistent entries (something no other answer here does....)

assuming you don't have huge numbers of entries a recursive function is easiest:

def merge(a, b, path=None):
    "merges b into a"
    if path is None: path = []
    for key in b:
        if key in a:
            if isinstance(a[key], dict) and isinstance(b[key], dict):
                merge(a[key], b[key], path + [str(key)])
            elif a[key] == b[key]:
                pass # same leaf value
                raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
            a[key] = b[key]
    return a

# works
print(merge({1:{"a":"A"},2:{"b":"B"}}, {2:{"c":"C"},3:{"d":"D"}}))
# has conflict
merge({1:{"a":"A"},2:{"b":"B"}}, {1:{"a":"A"},2:{"b":"C"}})

note that this mutates a - the contents of b are added to a (which is also returned). if you want to keep a you could call it like merge(dict(a), b).

agf pointed out (below) that you may have more than two dicts, in which case you can use:

reduce(merge, [dict1, dict2, dict3...])

where everything will be added to dict1.

[note - i edited my initial answer to mutate the first argument; that makes the "reduce" easier to explain]

ps in python 3, you will also need from functools import reduce

share|improve this answer
You can then stick this inside a reduce or the equivalent loop to work with an arbitrary number of dicts instead of two. However, I'm not sure this does what he wants either (he wasn't clear), You end up with 2: {'c': {'z': {'y': {'info1': 'value', 'info2': 'value2'}}}, 'b': {'info1': 'value', 'info2': 'value2'}} for his second example, I'm not sure whether he wants the z and y flattened up or not? –  agf Aug 26 '11 at 13:13
they are directory structures so i don't think s/he wants anything flattened? oh, sorry, missed "multiple dictionaries". yes, reduce would be good. will add that. –  andrew cooke Aug 26 '11 at 13:14
This does exactly what I wanted! I'm sorry I wasn't clear enough... I thought I was okay with Python, seems not :-/ I needed a recursive function because of the nested dicts, this one works and I can understand it :) I do not seem to be able to make it work with reduce though... –  Hydex Aug 26 '11 at 14:37
i updated the code a while ago to make it work better with reduce. the current version seems ok to me - can you post an error? for example, this works: print(reduce(merge, [{1:{"a":"A"},2:{"b":"B"}}, {2:{"c":"C"},3:{"d":"D"}}, {7:"foo"}])) –  andrew cooke Aug 26 '11 at 14:43
That may be a Python2 problem, I'm not sure:I do have a TypeError, None typeobject on line 5, because a is None. Command is reduce(merge, [dict1, dict2, dict3, dict4]) –  Hydex Aug 26 '11 at 14:54
show 4 more comments

Easiest way i can think of is :


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


{1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}}
share|improve this answer
add comment

This version of the function will account for N number of dictionaries, and only dictionaries -- no improper parameters can be passed, or it will raise a TypeError. The merge itself accounts for key conflicts, and instead of overwriting data from a dictionary further down the merge chain, it creates a set of values and appends to that; no data is lost.

It might not be the most effecient on the page, but it's the most thorough and you're not going to lose any information when you merge your 2 to N dicts.

def merge_dicts(*dicts):
    if not reduce(lambda x, y: isinstance(y, dict) and x, dicts, True):
        raise TypeError, "Object in *dicts not of type dict"
    if len(dicts) < 2:
        raise ValueError, "Requires 2 or more dict objects"

    def merge(a, b):
        for d in set(a.keys()).union(b.keys()):
            if d in a and d in b:
                if type(a[d]) == type(b[d]):
                    if not isinstance(a[d], dict):
                        ret = list({a[d], b[d]})
                        if len(ret) == 1: ret = ret[0]
                        yield (d, sorted(ret))
                        yield (d, dict(merge(a[d], b[d])))
                    raise TypeError, "Conflicting key:value type assignment"
            elif d in a:
                yield (d, a[d])
            elif d in b:
                yield (d, b[d])
                raise KeyError

    return reduce(lambda x, y: dict(merge(x, y)), dicts[1:], dicts[0])

print merge_dicts({1:1,2:{1:2}},{1:2,2:{3:1}},{4:4})

output: {1: [1, 2], 2: {1: 2, 3: 1}, 4: 4}

share|improve this answer
add comment

One issue with this question is that the values of the dict can be arbitrarily complex pieces of data. Based upon these and other answers I came up with this code:

class YamlReaderError(Exception):

def data_merge(a, b):
    """merges b into a and return merged result

    NOTE: tuples and arbitrary objects are not handled as it is totally ambiguous what should happen"""
    key = None
    # ## debug output
    # sys.stderr.write("DEBUG: %s to %s\n" %(b,a))
        if a is None or isinstance(a, str) or isinstance(a, unicode) or isinstance(a, int) or isinstance(a, long) or isinstance(a, float):
            # border case for first run or if a is a primitive
            a = b
        elif isinstance(a, list):
            # lists can be only appended
            if isinstance(b, list):
                # merge lists
                # append to list
        elif isinstance(a, dict):
            # dicts must be merged
            if isinstance(b, dict):
                for key in b:
                    if key in a:
                        a[key] = data_merge(a[key], b[key])
                        a[key] = b[key]
                raise YamlReaderError('Cannot merge non-dict "%s" into dict "%s"' % (b, a))
            raise YamlReaderError('NOT IMPLEMENTED "%s" into "%s"' % (b, a))
    except TypeError, e:
        raise YamlReaderError('TypeError "%s" in key "%s" when merging "%s" into "%s"' % (e, key, b, a))
    return a

My use case is merging YAML files where I only have to deal with a subset of possible data types. Hence I can ignore tuples and other objects. For me a sensible merge logic means

  • replace scalars
  • append lists
  • merge dicts by adding missing keys and updating existing keys

Everything else and the unforeseens results in an error.

share|improve this answer
add comment

I've been testing your solutions and decided to use this one in my project:

def mergedicts(dict1, dict2, conflict, no_conflict):
    for k in set(dict1.keys()).union(dict2.keys()):
        if k in dict1 and k in dict2:
            yield (k, conflict(dict1[k], dict2[k]))
        elif k in dict1:
            yield (k, no_conflict(dict1[k]))
            yield (k, no_conflict(dict2[k]))


#this helper function allows for recursion and the use of reduce
def f2(x, y):
    return dict(mergedicts(x, y, f2, lambda x: x))

print dict(mergedicts(dict1, dict2, f2, lambda x: x))
print dict(reduce(f2, [dict1, dict2]))

Passing functions as parameteres is key to extend jterrace solution to behave as all the other recursive solutions.

share|improve this answer
add comment

The code will depend on your rules for resolving merge conflicts, of course. Here's a version which can take an arbitrary number of arguments and merges them recursively to an arbitrary depth, without using any object mutation. It uses the following rules to resolve merge conflicts:

  • dictionaries take precedence over non-dict values ({"foo": {...}} takes precedence over {"foo": "bar"})
  • later arguments take precedence over earlier arguments (if you merge {"a": 1}, {"a", 2}, and {"a": 3} in order, the result will be {"a": 3})
    from collections import Mapping
except ImportError:
    Mapping = dict

def merge_dicts(*dicts):                                                            
    Return a new dictionary that is the result of merging the arguments together.   
    In case of conflicts, later arguments take precedence over earlier arguments.   
    updated = {}                                                                    
    # grab all keys                                                                 
    keys = set()                                                                    
    for d in dicts:                                                                 
        keys = keys.union(set(d))                                                   

    for key in keys:                                                                
        values = [d[key] for d in dicts if key in d]                                
        # which ones are mapping types? (aka dict)                                  
        maps = [value for value in values if isinstance(value, Mapping)]            
        if maps:                                                                    
            # if we have any mapping types, call recursively to merge them          
            updated[key] = merge_dicts(*maps)                                       
            # otherwise, just grab the last value we have, since later arguments    
            # take precedence over earlier arguments                                
            updated[key] = values[-1]                                               
    return updated  
share|improve this answer
add comment

Here's an easy way to do it using generators:

def mergedicts(dict1, dict2):
        if k in dict1 and k in dict2:
            yield (k, dict(mergedicts(dict1[k], dict2[k])))
        elif k in dict1: yield (k, dict1[k])
        else: yield (k, dict2[k])


print dict(mergedicts(dict1,dict2))

This prints:

share|improve this answer
if you want to keep the generator theme you could chain(dict1.keys(), dict2.keys()) –  andrew cooke Aug 26 '11 at 14:05
Wouldn't that get duplicate keys? –  jterrace Aug 26 '11 at 14:26
This one seems to do the work, at least on my set of data, but as I never understood yield and generators well I'm pretty much lost as to why, but I'm gonna try a bit harder, might be useful! –  Hydex Aug 26 '11 at 14:38
ah, yes, it would get duplicate keys. you'd still need to wrap it in a set, sorry. –  andrew cooke Aug 26 '11 at 14:48
I found this specially helpfull. But the nicesting would be to let the function to solve the conflicts as a parameter. –  mentatkgs May 24 '12 at 18:26
add comment

This should help in merging all items from dict2 into dict1:

for item in dict2:
    if item in dict1:
        for leaf in dict2[item]:
            dict1[item][leaf] = dict2[item][leaf]
        dict1[item] = dict2[item]

Please test it and tell us whether this is what you wanted.


The above mentioned solution merges only one level, but correctly solves the example given by OP. To merge multiple levels, the recursion should be used.

share|improve this answer
He's got an arbitrary depth of nesting –  agf Aug 26 '11 at 12:55
That can be rewritten simply as for k,v in dict2.iteritems(): dict1.setdefault(k,{}).update(v). But as @agf pointed out, this does not merge the nested dicts. –  Shawn Chin Aug 26 '11 at 13:09
@agf: Correct, so it seems OP needs solution employing recurrence. Thanks to the fact dictionaries are mutable, this should be quite easy to be done. But I think the question is not specific enough to tell what should happen when we come up with places with different levels of depths (eg. trying to merge {'a':'b'} with {'a':{'c':'d'}). –  Tadeck Aug 26 '11 at 13:15
add comment

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))
            output[item] = value
    for item, value in dictionary2.iteritems():
         output[item] = value
    return output
share|improve this answer
add comment

Your Answer


