If I have 2 dicts as follows:
d1 = {(\'unit1\',\'test1\'):2,(\'unit1\',\'test2\'):4}
d2 = {(\'unit1\',\'test1\'):2,(\'unit1\',\'test2\'):\'\'}
Here's an in-place solution (it modifies d2):
# assumptions: d2 is a temporary dict that can be discarded
# d1 is a dict that must be modified in place
# the modification is adding keys from d2 into d1 that do not exist in d1.
def update_non_existing_inplace(original_dict, to_add):
to_add.update(original_dict) # to_add now holds the "final result" (O(n))
original_dict.clear() # erase original_dict in-place (O(1))
original_dict.update(to_add) # original_dict now holds the "final result" (O(n))
return
Here's another in-place solution, which is less elegant but potentially more efficient, as well as leaving d2 unmodified:
# assumptions: d2 is can not be modified
# d1 is a dict that must be modified in place
# the modification is adding keys from d2 into d1 that do not exist in d1.
def update_non_existing_inplace(original_dict, to_add):
for key in to_add.iterkeys():
if key not in original_dict:
original_dict[key] = to_add[key]
d2.update(d1)
instead of dict(d2.items() + d1.items())
In case when you have dictionaries with the same size and keys you can use the following code:
dict((k,v if k in d2 and d2[k] in [None, ''] else d2[k]) for k,v in d1.iteritems())
Just switch the order:
z = dict(d2.items() + d1.items())
By the way, you may also be interested in the potentially faster update method.
In Python 3, you have to cast the view objects to lists first:
z = dict(list(d2.items()) + list(d1.items()))
If you want to special-case empty strings, you can do the following:
def mergeDictsOverwriteEmpty(d1, d2):
res = d2.copy()
for k,v in d2.items():
if k not in d1 or d1[k] == '':
res[k] = v
return res
to do this we can just create a dict without the empty values and then merge them together this way:
d1 = {'a':1, 'b':1, 'c': '', 'd': ''}
d2 = {'a':2, 'c':2, 'd': ''}
merged_non_zero = {
k: (d1.get(k) or d2.get(k))
for k in set(d1) | set(d2)
}
print(merged_non_zero)
outputs:
{'a': 1, 'b': 1, 'c': 2, 'd': ''}
a
-> prefer first value from d1 as 'a' exists on both d1 and d2b
-> only exists on d1c
-> non-zero on d2d
-> empty string on bothThe above code will create a dictionary using dict comprehension.
if d1
has the value and its non-zero value (i.e. bool(val) is True
), it'll use d1[k]
value, otherwise it'll take d2[k]
.
notice that we also merge all keys of the two dicts as they may not have the exact same keys using set union - set(d1) | set(d2)
.
unless using obsolete version of python you better off using this.
Pythonic & faster way for dict unpacking:
d1 = {'a':1, 'b':1}
d2 = {'a':2, 'c':2}
merged = {**d1, **d2} # priority from right to left
print(merged)
{'a': 2, 'b': 1, 'c': 2}
its simpler and also faster than the dict(list(d2.items()) + list(d1.items()))
alternative:
d1 = {i: 1 for i in range(1000000)}
d2 = {i: 2 for i in range(2000000)}
%timeit dict(list(d1.items()) + list(d2.items()))
402 ms ± 33.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit {**d1, **d2}
144 ms ± 1.12 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
more on this from PEP448:
The keys in a dictionary remain in a right-to-left priority order, so {**{'a': 1}, 'a': 2, **{'a': 3}} evaluates to {'a': 3}. There is no restriction on the number or position of unpackings.
Python 2.7. Updates d2 with d1 key/value pairs, but only if d1 value is not None,'' (False):
>>> d1 = dict(a=1,b=None,c=2)
>>> d2 = dict(a=None,b=2,c=1)
>>> d2.update({k:v for k,v in d1.iteritems() if v})
>>> d2
{'a': 1, 'c': 2, 'b': 2}