Merging two dictionaries

  • Thread starter Douglas Garstang
  • Start date
D

Douglas Garstang

Anyone,

I have the two dictionaries below. How can I merge them, such that:

1. The cluster dictionary contains the additional elements from the
default dictionary.
2. Nothing is removed from the cluster dictionary.

The idea here is that the two dictionaries are read from different
files where, if the value isn't found in the cluster dictionary, it's
pulled from the default one, and I can have a new dictionary
reflecting this. The update() method on dictionaries doesn't seem to
work. The resulting dictionary always seems to be the one passed as a
parameter.

default = {
'cluster': {
'platform': {
'elements': {
'data_sources': {
'elements': {
'db_min_pool_size': 10
},
},
},
},
}
}

cluster = {
'cluster': {
'name': 'Customer 1',
'description': 'Production',
'environment': 'production',
'platform': {
'elements': {
'data_source': {
'elements': {
'username': 'username',
'password': 'password'
},
},
},
},
}
}

The resulting dictionary would therefore look like this:

new_dict = {
'cluster': {
'name': 'Customer 1',
'description': 'Production',
'environment': 'production',
'platform': {
'elements': {
'data_source': {
'elements': {
'username': 'username',
'password': 'password',
'db_min_pool_size': 10 # This was added from
the default.
},
},
},
},
}
}


Thanks,
Doug.

--
Regards,

Douglas Garstang
http://www.linkedin.com/in/garstang
Email: (e-mail address removed)
Cell: +1-805-340-5627
 
P

Paul Rubin

Douglas Garstang said:
default = {...
'data_sources': { ...
cluster = {...
'data_source': { ...

Did you want both of those to say the same thing instead of one
of them being 'data_source' and the other 'data_sources' ?

If yes, then the following works for me:

def merge(cluster, default):
# destructively merge default into cluster
for k,v in cluster.iteritems():
if k in default and type(v)==dict:
assert type(default(k))==dict
merge(v,default[k])
for k,v in default.iteritems():
if k not in cluster:
cluster[k] = v
 
P

Peter Otten

Douglas said:
I have the two dictionaries below. How can I merge them, such that:

1. The cluster dictionary contains the additional elements from the
default dictionary.
2. Nothing is removed from the cluster dictionary.

def inplace_merge(default, cluster):
assert isinstance(default, dict)
assert isinstance(cluster, dict)

d = set(default)
c = set(cluster)
default_only = d - c
both = d & c
for key in both:
dv = default[key]
cv = cluster[key]
if isinstance(cv, dict):
inplace_merge(dv, cv)
cluster.update((dk, default[dk]) for dk in default_only)

should work once you've fixed your example dicts.

Peter
 
D

Douglas Garstang

Douglas Garstang said:
default = {...
                'data_sources': { ...
cluster = {...
                'data_source': { ...

Did you want both of those to say the same thing instead of one
of them being 'data_source' and the other 'data_sources' ?

If yes, then the following works for me:

   def merge(cluster, default):
       # destructively merge default into cluster
       for k,v in cluster.iteritems():
           if k in default and type(v)==dict:
               assert type(default(k))==dict
               merge(v,default[k])
       for k,v in default.iteritems():
           if k not in cluster:
               cluster[k] = v

Hmmm, using that gives me:

Traceback (most recent call last):
File "./test4.py", line 48, in ?
merge(cluster, default)
File "./test4.py", line 42, in merge
assert type(default(k))==dict
TypeError: 'dict' object is not callable

where line 42 is 'assert type(default(k))==dict', and the inputs are:

default = {
'cluster': {
'platform': {
'elements': {
'data_sources': {
'elements': {
'db_min_pool_size': 10
},
},
},
},
}
}

cluster = {
'cluster': {
'name': 'Customer 1',
'description': 'Customer Production',
'environment': 'production',
'platform': {
'elements': {
'data_source': {
'elements': {
'username': 'username',
'password': 'password'
},
},
},
},
}
}

and it's called with:

merge(cluster, default)

Doug.
 
P

Peter Otten

Douglas said:
If yes, then the following works for me:

def merge(cluster, default):
# destructively merge default into cluster
for k,v in cluster.iteritems():
if k in default and type(v)==dict:
assert type(default(k))==dict
merge(v,default[k])
for k,v in default.iteritems():
if k not in cluster:
cluster[k] = v

Hmmm, using that gives me:

Traceback (most recent call last):
File "./test4.py", line 48, in ?
merge(cluster, default)
File "./test4.py", line 42, in merge
assert type(default(k))==dict
TypeError: 'dict' object is not callable

where line 42 is 'assert type(default(k))==dict', and the inputs are:

Not making an attempt to understand the code that you are about to use?

default(k)

should be

default[k]

Peter
 
D

Douglas Garstang

Douglas said:
I have the two dictionaries below. How can I merge them, such that:

1. The cluster dictionary contains the additional elements from the
default dictionary.
2. Nothing is removed from the cluster dictionary.

def inplace_merge(default, cluster):
   assert isinstance(default, dict)
   assert isinstance(cluster, dict)

   d = set(default)
   c = set(cluster)
   default_only = d - c
   both = d & c
   for key in both:
       dv = default[key]
       cv = cluster[key]
       if isinstance(cv, dict):
           inplace_merge(dv, cv)
   cluster.update((dk, default[dk]) for dk in default_only)

should work once you've fixed your example dicts.

Peter

Wooo! I think that did it!
 
P

Paul Rubin

Douglas Garstang said:
where line 42 is 'assert type(default(k))==dict', and the inputs are:

Woops, cut and paste error. default(k) should say default[k]. Or you
could remove the assertion altogether.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,059
Latest member
cryptoseoagencies

Latest Threads

Top