Home > Software engineering >  Flatten nested dictionary and overwrite values
Flatten nested dictionary and overwrite values

Time:09-28

I have a nested dictionary which I want to flatten while overwriting values of duplicate keys. Example input looks like this:

{
    'abc': 1,
    'foo': 2
    'cba': {'abc': 3, 'baz': {
        'foo': 4
    }}
}

The goal is to overwrite values of keys in the top level dict with a value of the same key in a lower level dict, where the key in the lowest level dict is ruling.

and the output needs to be this:

{
    'abc': 3,
    'foo': 4,
    'cba': {'abc': 3, 'baz': {
        'foo': 4
    }}
}

I was trying to find a solution on SO but couldn't find one... Hopefully someone can help me out :)

CodePudding user response:

Not sure how robust this is, but I guess this is what you are looking for (credit to https://stackoverflow.com/a/6027615/5417511):

import collections

d = {
    'abc': 1,
    'foo': 2,
    'cba': {'abc': 3, 'baz': {
        'foo': 4
    }}
}

def flatten(d):
    items = []
    for k, v in d.items():
        if isinstance(v, collections.MutableMapping):
            items.extend(flatten(v).items())
        else:
            items.append((k, v))
    return dict(items)

d.update(flatten(d))
print(d)
{'abc': 3, 'foo': 4, 'cba': {'abc': 3, 'baz': {'foo': 4}}}

CodePudding user response:

The code below finds the maximum depth value for each key and then recursively updates the original input:

from collections import defaultdict
data = {'abc': 1, 'foo': 2, 'cba': {'abc': 3, 'baz': {'foo': 4}}}
def levels(d, c = 0):
   for a, b in d.items():
      yield from [(c, a, b)] if not isinstance(b, dict) else levels(b, c 1)

l = defaultdict(dict)
for _l, a, b in levels(data):
   l[a][_l] = b

def new_d(d):
   return {a:new_d(b) if isinstance(b, dict) else l[a][max(l[a])] for a, b in d.items()}

result = new_d(data)

Output:

{'abc': 3, 'foo': 4, 'cba': {'abc': 3, 'baz': {'foo': 4}}}

CodePudding user response:

you look probably for something like

ndir = {
    'abc': 1,
    'foo': 2,
    'cba': {'abc': 3, 'baz': { 'foo': 4 }}
}

print(ndir)

res = {}
def GetContent(ndir):
  for k, v in ndir.items():
    if isinstance(v, dict):
      GetContent(v)
    else:
      res[k]=v

GetContent(ndir)
print(res)
  • Related