Home > Software engineering >  Python3 Merge two dictionaries based on sub dictionaries keys w/o for loop
Python3 Merge two dictionaries based on sub dictionaries keys w/o for loop

Time:10-09

Maybe this is impossible but without a for loop through each key in a given dictionary merge the two based on the key in the dictionary

Given :

dict1 = { 'APPL' : { 'cp': 1, 'sed': 'bull'}, 'BAC' : { 'cp': 1, 'sed': 'bull'}}
dict2 = { 'APPL' : { 'tp': 100}}
dict3 = dict1 | dict2  ## python ≥3.9 only
print(dict3)
{'APPL': {'tp': 100}, 'BAC': {'cp': 1, 'sed': 'bull'}}
dict1.update(dict2)
print(dict1)
{'APPL': {'tp': 100}, 'BAC': {'cp': 1, 'sed': 'bull'}} 

Desired output

{'APPL': {'tp': 100,'cp': 1, 'sed': 'bull'}, 'BAC': {'cp': 1, 'sed': 'bull'}} 

I can do it now with a for loop , just wondering if there is a more elegant solution

CodePudding user response:

Do:

dict1 = {'APPL': {'cp': 1, 'sed': 'bull'}, 'BAC': {'cp': 1, 'sed': 'bull'}}
dict2 = {'APPL': {'tp': 100}}

res = {key: {**value, **dict2.get(key, {})} for key, value in dict1.items()}
print(res)

Output

{'APPL': {'cp': 1, 'sed': 'bull', 'tp': 100}, 'BAC': {'cp': 1, 'sed': 'bull'}}

CodePudding user response:

No, this isn't possible without iteration. You could use a custom joiner function and then reduce a list of dictionaries however:

data = [{'BAC': {'a': 40}, 'XYZ': {'c': 81, 'b': 16}, 'ABC': {'b': 85}},
        {'APPL': {'b': 55},
         'BAC': {'b': 16, 'f': 59},
         'ABC': {'d': 9, 'c': 43},
         'XYZ': {'b': 82}},
        {'ABC': {'b': 43, 'c': 35},
         'APPL': {'f': 17, 'a': 1, 'd': 16},
         'BAC': {'f': 35, 'a': 1},
         'XYZ': {'a': 2, 'c': 55}},
        {'BAC': {'f': 4, 'd': 87},
         'XYZ': {'d': 31, 'f': 92},
         'APPL': {'b': 18, 'a': 74, 'c': 69}},
        {'XYZ': {'d': 84, 'f': 49},
         'ABC': {'d': 88, 'a': 82, 'f': 96},
         'APPL': {'a': 23},
         'BAC': {'b': 40}},
        {'BAC': {'c': 88, 'd': 38},
         'APPL': {'c': 48, 'b': 30},
         'ABC': {'d': 95, 'b': 38},
         'XYZ': {'d': 90, 'a': 5}}]


def join_dict(d1, d2):
    result = {k: {**d1[k], **d2[k]} for k in d1}
    result.update({k: {**d1[k], **d2[k]} for k in d2})
    return result
>>> import functools
>>> functools.reduce(join_dict, data)
{'XYZ': {'a': 39, 'f': 78, 'c': 42, 'd': 30, 'b': 24},
 'ABC': {'c': 22, 'f': 69, 'a': 8, 'b': 51, 'd': 70},
 'APPL': {'d': 19, 'b': 35, 'a': 6, 'f': 33, 'c': 64},
 'BAC': {'f': 97, 'c': 38, 'd': 1, 'b': 63, 'a': 91}}

Of course, this will overwrite any common values in the sub-dictionaries. Assuming that isn't an issue for you, this should work fine as a "more elegant solution".

  • Related