Combining Multiple Mappings into a Single Mapping
Problem
- You have multiple dictionaries or mappings that you want to logically combine into a single mapping to perform certain operations, such as looking up values or checking for the existence of keys.
Solution
- An easy way to do this is to use the
ChainMap
class from the collections
module.
a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }
from collections import ChainMap
c = ChainMap(a,b)
print(c['x'])
print(c['y'])
print(c['z'])
1
2
3
Discussion
- A ChainMap takes multiple mappings and makes them logically appear as one. However, the mappings are not literally merged together.
- If there are duplicate keys, the values from the first mapping get used. Thus, the entry
c['z']
in the example would always refer to the value in dictionary a, not the value in dictionary b.
- Operations that mutate the mapping always affect the first mapping listed.
c['z'] = 10
c['w'] = 40
del c['x']
print(a)
print(b)
{'z': 10, 'w': 40}
{'y': 2, 'z': 4}
del c['y']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
/Users/tvu/anaconda/envs/py35/lib/python3.5/collections/__init__.py in __delitem__(self, key)
928 try:
--> 929 del self.maps[0][key]
930 except KeyError:
KeyError: 'y'
During handling of the above exception, another exception occurred:
KeyError Traceback (most recent call last)
<ipython-input-7-df3e26fa6544> in <module>()
----> 1 del c['y']
/Users/tvu/anaconda/envs/py35/lib/python3.5/collections/__init__.py in __delitem__(self, key)
929 del self.maps[0][key]
930 except KeyError:
--> 931 raise KeyError('Key not found in the first mapping: {!r}'.format(key))
932
933 def popitem(self):
KeyError: "Key not found in the first mapping: 'y'"
- As an alternative to ChainMap, you might consider merging dictionaries together using the
update()
method.
a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }
merged = dict(b)
merged.update(a)
print(merged['x'])
print(merged['y'])
print(merged['z'])
1
2
3
- This works, but it requires you to make a completely separate dictionary object (or destructively alter one of the existing dictionaries). Also, if any of the original diction‐ aries mutate, the changes don’t get reflected in the merged dictionary.
a['x'] = 13
merged['x']
1
- A ChainMap uses the original dictionaries, so it doesn’t have this behavior.
a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }
merged = ChainMap(a, b)
print(merged['x'])
1
a['x'] = 42
print(merged['x'])
print(a['x'])
42
42