Search code examples
python-3.xodoo-11

Merge between 2 nested dictionaries and obtain single dict


I know there are similar question about this. I tried searching example and answer but I don't have a clear solution. I am stuck at this. I have 2 nested dictionaries and I want to merge it into single dict. It is in JSON version but running in python too is fine.

x = {'folders': [
{'id': 124, 'name': 'Leads', 'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0}, 
{'id': 123, 'name': 'Alumni', 'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0}, 
]}
y = {'folders':[{'id': 124,'name':'Leads'}, {'id': 121,'name': 'Member'},{'id':123,'name':'Alumni'}]}

What I want:

result = {'folders': [
{'id': 124, 'name': 'Leads', 'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0}, 
{'id': 123, 'name': 'Alumni', 'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0},
{'id': 121, 'name': 'Member'} 
]}

Please help me.


Solution

  • The general idea is to group the elements we consider identical by some key with groupby, which the tuple (x[id] , x[name]), and then combine all excess elements other than our key per group with ChainMap.

    from pprint import pprint
    from itertools import groupby
    from collections import ChainMap
    
    a = {
        'folders': [
            { 'id': 124, 'name': 'Leads',  'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0 }, 
            { 'id': 123, 'name': 'Alumni', 'totalBlacklisted': 0, 'uniqueSubscribers': 0, 'totalSubscribers': 0 }, 
        ]
    }
    
    b = {
        'folders': [
            { 'id': 124, 'name': 'Leads'  },
            { 'id': 121, 'name': 'Member' },
            { 'id': 123, 'name': 'Alumni' }
        ]
    }
    
    def key(x):
        return (x['id'], x['name'])
    
    def merge(a, b, key):
        c = a + b
        groups = groupby(sorted(c, key=key), key=key)
        merged = [dict(ChainMap(*g)) for _, g in groups]
        return merged
    
    pprint({'folders': merge(a['folders'], b['folders'], key=key)})
    > {'folders': [{'id': 121, 'name': 'Member'},
                   {'id': 123,
                    'name': 'Alumni',
                    'totalBlacklisted': 0,
                    'totalSubscribers': 0,
                    'uniqueSubscribers': 0},
                   {'id': 124,
                    'name': 'Leads',
                    'totalBlacklisted': 0,
                    'totalSubscribers': 0,
                    'uniqueSubscribers': 0}]}
    

    If you want to look at the output of groupby, run this modified merge function:

    def merge(a, b, key):
        c = a + b
        groups = groupby(sorted(c, key=key), key=key)
        merged = [(k, list(g)) for k, g in groups]
        return merged