How to merge Python N dictionaries without overwriting values?

I have this list of dictionaries:

list_of_ds = [
    {'a': [1, 2], 'b': [4, 5], 'c': [6, 7]},
    {'a': [4], 'b': [56], 'c': [46]},
    {'a': [92], 'b': [65], 'c': [43]}
]

and I want this as a conclusion:

{'a': [1, 2, 4, 92], 'b': [4, 5, 56, 65], 'c': [6, 7, 46, 43]}

Still...

I tried

d_of_ds = reduce(lambda d1, d2: d1.update(d2), list_of_ds)

gives: AttributeError: 'NoneType' object has no attribute 'update'

I tried

d_of_ds = reduce(lambda d1, d2: d1.update(d2) or d1, list_of_ds, {})

Overwrites each iteration: {'a': [92], 'b': [65], 'c': [43]}

I tried

d_of_ds = {k: v for d in list_of_ds for k, v in d.items()}

Overwrites each iteration: {'a': [92], 'b': [65], 'c': [43]}

+4
source share
3 answers

Using is reducenot a good idea in this case. In addition, your lambda function has incorrect logic in general, because you are trying to update all dictionaries together, and not their elements see the following:

>>> a={'a':[1,2], 'b':[4,5],'c':[6,7]}
>>> a.update({'a':[4], 'b':[56],'c':[46]})
>>> a
{'a': [4], 'c': [46], 'b': [56]}

But, as a more efficient way, you can use the method dict.setdefault:

>>> new={}
>>> for d in list_of_ds:
...    for i,j in d.items():
...       new.setdefault(i,[]).extend(j)
... 
>>> new
{'a': [1, 2, 4, 92], 'c': [6, 7, 46, 43], 'b': [4, 5, 56, 65]}

Also you can use collections.defaultdict:

>>> from collections import defaultdict
>>> d=defaultdict(list)
>>> for sub in list_of_ds:
...    for i,j in sub.items():
...       d[i].extend(j)
... 
>>> d
defaultdict(<type 'list'>, {'a': [1, 2, 4, 92], 'c': [6, 7, 46, 43], 'b': [4, 5, 56, 65]})
+4
source

Not very effective, but pretty reducesolution:

def f(x, y):
    return {k: x.get(k, []) + y.get(k, []) for k in set(x).union(y)}

from functools import reduce
reduce(f, list_of_ds) # {'b': [4, 5, 56, 65], 'a': [1, 2, 4, 92], 'c': [6, 7, 46, 43]}

, collections.defaultdict:

from collections import defaultdict

def f(list_of_ds):
    new = defaultdict(list)
    for d in list_of_ds:
        for k, v in d.items():
            new[k].extend(v)
    return new # or dict(new), to obtain a 'dict' object

f(list_of_ds) # {'a': [1, 2, 4, 92], 'b': [4, 5, 56, 65], 'c': [6, 7, 46, 43]}
+2

-

>>> new_dict = {}
>>> new_dict
{}
>>> for dct in list_of_ds:
        for key,val in dct.items():
            if key not in new_dict.keys(): new_dict[key] = val
            else: new_dict[key].extend(val)


>>> new_dict
{'a': [1, 2, 4, 92], 'c': [6, 7, 46, 43], 'b': [4, 5, 56, 65]}
0

Source: https://habr.com/ru/post/1584361/


All Articles