Suren
Suren

Reputation: 207

Convert list of nested dictionary to a flat list of dictionary

I have a list of dictionaries in which few may be nested. I want to make it a flat list of dictionaries.
Here, Message is a list of dictionaries that has a key 'Message_content'.
I would like to pop out 'Message_content' in case if it contains a key Message.

The nesting could be to any level. I mean 'Message_content' might again contain 'Message' though the example shown here is for one level

Input

Message = [
    {'Message_content': {'Argument': [{'Arg_name': 'acl_name'}, {'Arg_name': 'acl_type'}],
                         'Message': {'Message_content': {'Argument': [{'Arg_name': 'cat_name'}, {'Arg_name': 'cat_enum'}]}}}},
    {'Message_content': {'Argument': [{'Arg_name': 'ac_name'}, {'Arg_name': 'ac_type'}]}}
       ]

Expected output:

Message = [
    {'Message_content': {'Argument': [{'Arg_name': 'acl_name'}, {'Arg_name': 'acl_type'}]}},
    {'Message_content': {'Argument': [{'Arg_name': 'cat_name'}, {'Arg_name': 'cat_enum'}]}},
    {'Message_content': {'Argument': [{'Arg_name': 'ac_name'}, {'Arg_name': 'ac_type'}]}}
    ]

Tried writing a recursive function but unable to handle the nesting.
Any help would be appreciated.

Upvotes: 2

Views: 602

Answers (1)

Seeker89
Seeker89

Reputation: 292

The recursion here is quite simple. You can tackle it like so:

input = [
    {'Message_content': {
            'Argument': [{ 'Arg_name': 'acl_name' }, { 'Arg_name': 'acl_type' }],
            'Message': { 'Message_content': { 'Argument': [{ 'Arg_name': 'cat_name' }, { 'Arg_name': 'cat_enum' }] } }
    }},
    { 'Message_content': { 'Argument': [{ 'Arg_name': 'ac_name' }, { 'Arg_name': 'ac_type' }] } }
]

def handle_element(elem, output):
    try:
        arg = elem["Message_content"]["Argument"]
        output.append(arg)
    except KeyError:
        pass
    try:
        msg = elem["Message_content"]["Message"]
        print "nested"
        handle_element(msg, output)
    except KeyError:
        print "not nested"


out = []
for elem in input:
    handle_element(elem, out)

print out

Alternatively, to avoid stack overflow due to recursive calls, you can transform it into an iterative process, using a list to track the elements to be handled. The way you insert the nested elements into the list will decide on the order of the nested things appearing in the output list. Here, you handle the nested structures at the end of the "queue":

message = [
    {'Message_content': {
            'Argument': [{ 'Arg_name': 'acl_name' }, { 'Arg_name': 'acl_type' }],
            'Message': { 'Message_content': { 'Argument': [{ 'Arg_name': 'cat_name' }, { 'Arg_name': 'cat_enum' }] } }
    }},
    { 'Message_content': { 'Argument': [{ 'Arg_name': 'ac_name' }, { 'Arg_name': 'ac_type' }] } }
]

elements_to_handle = message
def handle_element(elem, output):
    try:
        arg = elem["Message_content"]["Argument"]
        output.append(arg)
    except KeyError:
        pass
    try:
        msg = elem["Message_content"]["Message"]
        elements_to_handle.append(msg)
    except KeyError:
        pass


out = []
while len(elements_to_handle):
    handle_element(elements_to_handle.pop(), out)

print out

Upvotes: 2

Related Questions