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.

+3


source to share


6 answers


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:



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

+3


source


To avoid duplication if you are concatenating multiple lists of lists:



def updateDict(dict1, dict2):
   for key in dict1:
      if key in dict2:
         prev_values = set(dict1[key]) # create set to retain only unique values in list
         prev_values.update(dict2[key])
         dict1[key] = list(prev_values)

      

+1


source


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

      

0


source


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

      

0


source


Don't know a straightforward way, but this should work:

def combine_dicts(dict1,dict2):
    dict = {}
    for key1,list1 in dict1.items():
        for key2,list2 in dict2.items():
           if key1 == key2:
               dict[key1] = list1.extend(list2)
    return dict

      

0


source


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

      

0


source







All Articles