How to iterate through a nested dictionary with varying depth, and make a copy with value representing the path?

Question:

I have a dictionary

 {'n11' : 
        {'n12a':
               {'n13a' : 10 , 'n13b' : "some text"},
         'n12b':
                {'n13c' : 
                          {'n14a': 40}
                }
         },
   'n21': 
         {'n22a' : 20 }
 }

And I want to iterate through the dictionary until I reach a value which is not a dictionary, and replace it with the "full path" to that value.

 {'n11' : 
        {'n12a':
               {'n13a' : 'n11_n12a_n13a' , 'n13b' : 'n11_n12a_n13b'},
         'n12b':
                {'n13c' : 
                          {'n14a': 'n11_n12b_n13c_n14a'}
                }
         },
   'n21': 
         {'n22a' : 'n21_n22a' }
 }

I know how to iterate through a nested dictionary with the following function, but I don’t understand how to copy the same structure but with the updated value.

 def myprint(d,path=[]):
    for k, v in d.items():
        if isinstance(v, dict):
            path.append(k)
            myprint(v,path)
        else:
            print('_'.join(path))

  output:
  'n11_n12a_n13a'
  'n11_n12a_n13b'
  'n11_n12b_n13c_n14a'
  'n21_n22a'

But how do I get it into another dictionary?

Asked By: Kspr

||

Answers:

The most efficient way to do this would be using the same recursive function to not generate excess performance overhead. To copy the dictionary you can use copy.deepcopy() and then take that copy through the function, but replace the values instead of just printing the path:

import copy


data = {'n11': {'n12a': {'n13a': 10, 'n13b': "some text"}, 'n12b': {'n13c': {'n14a': 40}}}, 'n21': {'n22a': 20}}


def myreplace(d, path=[]):
for k, v in d.items():
    if isinstance(v, dict):
        myreplace(v, path + [k])
    else:
        print('_'.join(path + [k]))
        d[k] = '_'.join(path + [k])
return d


copy_of_data = copy.deepcopy(data)
copy_of_data = myreplace(copy_of_data)
print(data)
print(copy_of_data)

I had to modify the original function slightly to get it working.

Answered By: LTJ
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.