How to merge and properly update dictionaries in python (where value is a list)?
Let's say I have two dictates where values ββare lists (or sets are fine too, since the content is unique). For example:
dic1 = {'math': ['algebra', 'trigonometry', 'geometry']}
dic2 = {'math': ['calculus'], 'science': ['physics']}
dic2.update(dic1)
My desired output would be as follows:
{'math': ['algebra', 'trigonometry', 'geometry', 'calculus'], 'science': ['physics']}
but instead I get:
{'math': ['algebra', 'trigonometry', 'geometry'], 'science': ['physics']}
Essentially I want to merge the content when merging two dicts (I don't want to override, but keep both of them). Is there an easy way to do this? Note. In this example I gave, there are only two dictionaries. Although I haven't written any code yet, I would eventually like to iterate over several dictionaries and do this merge / update process in a loop, which might be helpful in suggesting an approach.
source to share
This can be expressed in a simple one-liner:
>>> {k: dic1.get(k, []) + dic2.get(k, []) for k in (set(dic1) | set(dic2))}
{'science': ['physics'], 'math': ['algebra', 'trigonometry', 'geometry', 'calculus']}
This combines three methods:
- union of two sets combines keys and eliminates duplicates.
- dict.get () provides a default empty list for missing keys.
- understanding a vocabulary creates a new vocabulary.
Core Python tooling often provides elegant solutions to basic primitive data management problems. I am often amazed at how well the instruments work together.
How does it help :-)
source to share
dict1 = {'math': ['algebra', 'trigonometry', 'geometry']}
dict2 = {'math': ['calclus'], 'science': ['physics']}
for key, value in dict1.items():
dict2.setdefault(key, []).extend(value)
>>> print(dict2)
{'science': ['physics'], 'math': ['calclus', 'algebra', 'trigonometry', 'geometry']}
If you want to keep both dictionary values ββdo this
from copy import deepcopy
dict1 = {'math': ['algebra', 'trigonometry', 'geometry']}
dict2 = {'math': ['calclus'], 'science': ['physics'], 'lol':['lol1']}
dict3 = deepcopy(dict2)
for key, value in dict1.items():
dict3.setdefault(key, []).extend(value)
>>>print(dict2)
{'science': ['physics'], 'math': ['calclus']}
>>>print(dict3)
{'science': ['physics'], 'math': ['calclus', 'algebra', 'trigonometry', 'geometry']}
source to share
This is an understandable error that will work if it dic1
does not contain keys that are not in dic2
:
dic3 = {k: v + dic1.get(k, list()) for k, v in dic2.items()}
Also, to make sure any missing keys from are dic1
added to the dict, you can add a loop afterwards for
.
for k, v in dic1.items():
if k not in dic3:
dic3.update({k: v})
source to share
You can create your own vocabulary to get the desired behavior. I'm not sure if this is the best way, but there is one possibility here:
import collections
class ListDict(collections.UserDict):
def update(self, other):
if isinstance(other, collections.Mapping):
for key, value in other.items():
self.data.setdefault(key, []).extend(value)
else:
raise NotImplementedError()
dic1 = ListDict({'math': ['algebra', 'trigonometry', 'geometry']})
dic2 = ListDict({'math': ['calculus'], 'science': ['physics']})
dic2.update(dic1)
print(dic2)
Output:
{'math': ['calculus', 'algebra', 'trigonometry', 'geometry'], 'science': ['physics']}
Please note that this is just the beginning that implements the desired behavior. Depending on what you are using it for, you can add more functionality. For example, only one of the calling methodsupdate
is implemented .
To prevent duplicate values ββin the resulting collections, you can use sets instead:
import collections
class SetDict(collections.UserDict):
def update(self, other):
if isinstance(other, collections.Mapping):
for key, value in other.items():
self.data[key] = self.data.get(key, set()).union(value)
else:
raise NotImplementedError()
dic3 = SetDict({'math': ['algebra', 'trigonometry']}) # may contain lists ...
dic4 = SetDict({'math': {'algebra', 'geometry'}}) # ... or sets
dic4.update(dic3)
print(dic4)
Output:
{'math': {'algebra', 'geometry', 'trigonometry'}}
source to share