3
def recursion(input_type):
    print('input_type ',input_type)
    if isinstance(input_type, dict):
        num = 0
        for k,v in input_type.items():
            if isinstance(v, dict):
                print('from recursion')
                recursion(v)
            elif isinstance(v, list):
                for j in v:
                    if isinstance(j, dict):
                        print('from recursion level 2')
                        recursion(j)
            else:
                temp_dict = {k:v}   
                print('type: ',type(temp_dict), k, v)
            print('num',num)
            num = num+1  

for i in list_:
    recursion(i)     

How to get the interim results from the recursion.

consider the input as shown below:

input: [{'a':a, 'b':b, 'c':[{'d':d, 'e':e}]}]
Updated input: [ {'a':a, 'b':b, 'c': { 'd':d, 'e': [ {'f':f, 'g':g}, {'f':f1, 'g':g1} ] } } ]

desired output: [{'a':a, 'b':b, 'd':d, 'f':f, 'g':g, 'f_new':f1, 'g_new':g1}]

If the key is duplicate then it should update such as 'f' to 'f_new' or something like that

Thank you in advance!!

dumb_coder
  • 315
  • 5
  • 21

1 Answers1

4

You can iterate over the dict items and if an item is a list, recursively flatten the dicts within it:

def f(o):
    return {a: b for k, v in o.items() for a, b in ((i for d in (v if isinstance(v, list)
        else (v,)) for i in f(d).items()) if isinstance(v, (list, dict)) else ((k, v),))}

so that given:

lst = [{'a': 'a', 'b': 'b', 'c': [{'d': 'd', 'e': 'e'}, {'f': [{'g': 'g'}]}]}]

[f(d) for d in lst] would return:

[{'a': 'a', 'b': 'b', 'd': 'd', 'e': 'e', 'g': 'g'}]

and that given:

lst = [{'a': 'a', 'b': 'b', 'c': {'d': 'd', 'e': {'f': 'f', 'g': 'g'}}}]

[f(d) for d in lst] would return:

[{'a': 'a', 'b': 'b', 'd': 'd', 'f': 'f', 'g': 'g'}]

To avoid collisions in merged keys, append _new to a duplicating key until it is found not pre-existing, in which case you cannot use comprehension:

def f(o):
    output = {}
    for k, v in o.items():
        for a, b in ((i for d in (v if isinstance(v, list) else (v,)) for i in f(d).items())
                if isinstance(v, (list, dict)) else ((k, v),)):
            while a in output:
                a += '_new'
            output[a] = b
    return output

so that given:

lst = [{'a': 'a', 'b': 'b', 'c': {'d': 'd', 'e': [{'f': 'f', 'g': 'g'}, {'f': 'f1', 'g': 'g1'}]}}]

[f(d) for d in lst] would return:

[{'a': 'a', 'b': 'b', 'd': 'd', 'f': 'f', 'g': 'g', 'f_new': 'f1', 'g_new': 'g1'}]

Demo: https://repl.it/@blhsing/NonstopSeveralActionscript

blhsing
  • 91,368
  • 6
  • 71
  • 106
  • 1
    I timed both the solutions and yours is way faster than mine. And it makes sense as I'm always building a new dictionary every time.+1 and deleted my solution. – Ch3steR Feb 25 '20 at 19:36
  • @Ch3steR Yes, but to be more precise, the main reason for the difference in efficiency is that my solution builds a new dict only for each recursion, while your solution builds a new dict for each item in a given dict for each recursion. – blhsing Feb 25 '20 at 19:59
  • @blhsing, can we do the same for both list and dict? Example: input[{'a':a, 'b':b, 'c':{'d':d, 'e':['f':f, 'g':g]}}] – dumb_coder Feb 27 '20 at 19:43
  • @DevanshuKhokhani Not sure what you mean by doing the same for both list and dict. Please update your question to clarify the logics. – blhsing Feb 27 '20 at 19:45
  • @blhsing, so the input will be a list that has many dictionary. Now within the list, a value from key, value pair can be either a dictionary or list. Just like this one. input[ {'a':a, 'b':b, 'c': { 'd':d, 'e': [ 'f':f, 'g':g ] } } ]. Is it possible to flatten this type of input? – dumb_coder Feb 27 '20 at 20:07
  • @blhsing, I have update the question with the updated input. Can you help me? – dumb_coder Feb 27 '20 at 20:10
  • 1
    I see. I've updated my answer accordingly then. Can you mark this answer as accepted if you find it to be correct? – blhsing Feb 27 '20 at 21:32
  • 1
    @blhsing. You saved my hours!! – dumb_coder Feb 27 '20 at 21:41
  • @blhsing, just an additional question. Can we force the dictionary to not overwrite any pre-existing key with new value but append the dictionary? – dumb_coder Feb 27 '20 at 21:52
  • @DevanshuKhokhani So the values will always be a list then? Please update your question with sample input and output for clarification. – blhsing Feb 27 '20 at 21:54
  • @DevanshuKhokhani Your updated expected output is invalid since dicts in Python can not have duplicating keys. – blhsing Feb 27 '20 at 21:59
  • @blhsing. I agree. That is why for me it is ok if the duplicate key can be renamed to something else – dumb_coder Feb 27 '20 at 22:01
  • 1
    @DevanshuKhokhani I've updated the answer accordingly then. – blhsing Feb 27 '20 at 22:10
  • 1
    @blhsing. This has solved all the issues. Thank you very much!!! – dumb_coder Feb 27 '20 at 22:13