Home > Back-end >  Merge/concatenate multiple dictionaries using main key
Merge/concatenate multiple dictionaries using main key

Time:06-26

I have four nested dictionaries:

    a = {
        1: {'a': 123, 'b': 222, 'c': 888},
        2: {'a': 333, 'b': 555, 'c': 345}}

    b = {
        1: {'d': 456, 'e': 333, 'f': 333},
        2: {'d': 555, 'e': 233, 'f': 433}}

    c = {
        1: {'g': 789, 'h': 444, 'i': 999},
        2: {'g': 456, 'h': 333, 'i': 333}}

    d = {
        1: {'j': 111, 'k': 555, 'l': 222},
        2: {'j': 456, 'k': 333, 'l': 333, 'm': 555}}

I want to concatenate/merge them into a new dictionary and group by the main key. The desired output is:

result = {
        1: {'a': 123, 'b': 222, 'c': 888, 'd': 456, 'e': 333, 'f': 333, 'g': 789, 'h': 444, 'i': 999, 'j': 111, 'k': 555, 'l': 222},
        2: {'a': 333, 'b': 555, 'c': 345, 'd': 555, 'e': 233, 'f': 433, 'g': 456, 'h': 333, 'i': 333, 'j': 456, 'k': 333, 'l': 333, 'm': 555}}

Each dictionary (a,b,c,d) has exactly 200 main keys (1 to 200) - I've only shown 2 entries each. There are no duplicate sub keys, but there are sometimes more subkeys in one than another (see "d").

I realize there are numerous very similar questions on stackoverflow, but the ones I found seem to involve something else (tuples, lists, combining only two dictionaries, etc.) and I have not been able to adapt any to my situation. An unsuccessful attempt (based on a similar question) that seemed logical given what I want the result to be:

result = {key: a[key]   b[key]   c[key]   d[key] for key in a}

CodePudding user response:

You can use reduce() with defaultdict() to build up the result. For each key in the (outer) dictionary, we accumulate the key-value pairs corresponding to the inner dictionary (i.e. dictionary that a key maps to) using reduce():

from functools import reduce
from collections import defaultdict

dictionaries = [a, b, c, d]

# Can use dict.__or__ in Python 3.9 , rather than dict(**x[k], **y[k])
result = reduce(
    lambda x, y: {k: dict(**x[k], **y[k]) for k in y},
    dictionaries, defaultdict(dict)
)
print(result)

This outputs:

{
 1: {'a': 123, 'b': 222, 'c': 888, 'd': 456, 'e': 333, 'f': 333, 'g': 789, 'h': 444, 'i': 999, 'j': 111, 'k': 555, 'l': 222},
 2: {'a': 333, 'b': 555, 'c': 345, 'd': 555, 'e': 233, 'f': 433, 'g': 456, 'h': 333, 'i': 333, 'j': 456, 'k': 333, 'l': 333, 'm': 555}
}

CodePudding user response:

Use the | operator to combine all the sub-dictionaries together:

import functools

result = {
    main_key: functools.reduce(
        dict.__or__,
        (sub_dicts[main_key] for sub_dicts in (a, b, c, d))
    )
    for main_key in a
}

CodePudding user response:

This is also an alternative way to solve your problem

dd = {}

for k in a:
    dd[k] = {**a[k], **b[k], **c[k], **d[k]}

Output:

{1: {'a': 123,
  'b': 222,
  'c': 888,
  'd': 456,
  'e': 333,
  'f': 333,
  'g': 789,
  'h': 444,
  'i': 999,
  'j': 111,
  'k': 555,
  'l': 222},
 2: {'a': 333,
  'b': 555,
  'c': 345,
  'd': 555,
  'e': 233,
  'f': 433,
  'g': 456,
  'h': 333,
  'i': 333,
  'j': 456,
  'k': 333,
  'l': 333,
  'm': 555}}

CodePudding user response:

You can use ** merging multi dict and create one dict from them:

>>> {k: {**v, **b.get(k,{}), **c.get(k,{}), **d.get(k, {})} for k,v in a.items()}

{1: {'a': 123,
  'b': 222,
  'c': 888,
  'd': 456,
  'e': 333,
  'f': 333,
  'g': 789,
  'h': 444,
  'i': 999,
  'j': 111,
  'k': 555,
  'l': 222},
 2: {'a': 333,
  'b': 555,
  'c': 345,
  'd': 555,
  'e': 233,
  'f': 433,
  'g': 456,
  'h': 333,
  'i': 333,
  'j': 456,
  'k': 333,
  'l': 333,
  'm': 555}}

CodePudding user response:

You can try using ** to merge multiple dicts together.

a = {
    1: {'a': 123, 'b': 222, 'c': 888},
    2: {'a': 333, 'b': 555, 'c': 345}}

b = {
    1: {'d': 456, 'e': 333, 'f': 333},
    2: {'d': 555, 'e': 233, 'f': 433}}

c = {
    1: {'g': 789, 'h': 444, 'i': 999},
    2: {'g': 456, 'h': 333, 'i': 333}}

d = {
    1: {'j': 111, 'k': 555, 'l': 222},
    2: {'j': 456, 'k': 333, 'l': 333, 'm': 555}}

result = {}
for i in range(1,len(a) 1):
    l = {**a[i], **b[i], **c[i], **d[i]}
    result[i] = l
    
print(result)
"""
{1: {'a': 123, 'b': 222, 'c': 888, 'd': 456, 'e': 333, 'f': 333, 'g': 789, 'h': 444, 'i': 999, 'j': 111, 'k': 555, 'l': 222}, 
 2: {'a': 333, 'b': 555, 'c': 345, 'd': 555, 'e': 233, 'f': 433, 'g': 456, 'h': 333, 'i': 333, 'j': 456, 'k': 333, 'l': 333, 'm': 555}}
"""

CodePudding user response:

you can use simply the or operation on dictionary

a =

 {1: {'a': 123, 'b': 222, 'c': 888},
    2: {'a': 333, 'b': 555, 'c': 345}}

b =

 {1: {'d': 456, 'e': 333, 'f': 333},
    2: {'d': 555, 'e': 233, 'f': 433}}

c =

 {1: {'g': 789, 'h': 444, 'i': 999},
    2: {'g': 456, 'h': 333, 'i': 333}}

d =

 {1: {'j': 111, 'k': 555, 'l': 222},
    2: {'j': 456, 'k': 333, 'l': 333, 'm': 555}}

result =

  {1: a[1] | b[1] | c[1] | d[1],
    2: a[2] | b[2] | c[2] | d[2]}

print(result)

output :

{1:

{'a': 123, 'b': 222, 'c': 888, 'd': 456, 'e': 333, 'f': 333, 'g': 789, 'h': 444, 'i': 999, 'j': 111, 'k': 555, 'l': 222},2: 
  {'a': 333, 'b': 555, 'c': 345, 'd': 555, 'e': 233, 'f': 433, 'g': 456, 'h':333, 'i': 333, 'j': 456, 'k': 333, 'l': 333, 'm': 555}

}

  • Related