Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to convert a nested OrderedDict to dict?

Tags:

I have a nested OrderedDict I would like to convert to a dict. Applying dict() on it apparently only converts the outermost layer of the last entry.

from collections import OrderedDict

od = OrderedDict(
    [
        (u'name', u'Alice'),
        (u'ID', OrderedDict(
            [
                (u'type', u'card'),
                (u'nr', u'123')
            ]
        )),
        (u'name', u'Bob'),
        (u'ID', OrderedDict(
            [
                (u'type', u'passport'),
                (u'nr', u'567')
            ]
        ))
    ]
)

print(dict(od))

Output:

{u'name': u'Bob', u'ID': OrderedDict([(u'type', u'passport'), (u'nr', u'567')])}

Is there a direct method to convert all the occurences?

like image 850
WoJ Avatar asked Jul 31 '14 08:07

WoJ


People also ask

How do I convert a nested list to a dictionary?

We can convert a nested list to a dictionary by using dictionary comprehension. It will iterate through the list. It will take the item at index 0 as key and index 1 as value.

What is the difference between OrderedDict and dict?

The OrderedDict is a subclass of dict object in Python. The only difference between OrderedDict and dict is that, in OrderedDict, it maintains the orders of keys as inserted. In the dict, the ordering may or may not be happen. The OrderedDict is a standard library class, which is located in the collections module.

How do you make a list into a dictionary?

To convert a list to dictionary, we can use list comprehension and make a key:value pair of consecutive elements. Finally, typecase the list to dict type.

How do I get rid of OrderedDict?

In fact, you should always use del to remove an item from a dictionary. dict. pop and dict. popitem are used to remove an item and return the removed item so that it can be saved for later.


2 Answers

Simplest solution is to use json dumps and loads

from json import loads, dumps
from collections import OrderedDict

def to_dict(input_ordered_dict):
    return loads(dumps(input_ordered_dict))

NOTE: The above code will work for dictionaries that are known to json as serializable objects. The list of default object types can be found here

So, this should be enough if the ordered dictionary do not contain special values.

EDIT: Based on the comments, let us improve the above code. Let us say, the input_ordered_dict might contain custom class objects that cannot be serialized by json by default. In that scenario, we should use the default parameter of json.dumps with a custom serializer of ours.

(eg):

from collections import OrderedDict as odict
from json import loads, dumps

class Name(object):
    def __init__(self, name):
        name = name.split(" ", 1)
        self.first_name = name[0]
        self.last_name = name[-1]

a = odict()
a["thiru"] = Name("Mr Thiru")
a["wife"] = Name("Mrs Thiru")
a["type"] = "test" # This is by default serializable

def custom_serializer(obj):
    if isinstance(obj, Name):
        return obj.__dict__

b = dumps(a) 
# Produces TypeError, as the Name objects are not serializable
b = dumps(a, default=custom_serializer)
# Produces desired output

This example can be extended further to a lot bigger scope. We can even add filters or modify the value to our necessity. Just add an else part to the custom_serializer function

def custom_serializer(obj):
    if isinstance(obj, Name):
        return obj.__dict__
    else:
        # Will get into this if the value is not serializable by default 
        # and is not a Name class object
        return None

The function that is given at the top, in case of custom serializers, should be:

from json import loads, dumps
from collections import OrderedDict

def custom_serializer(obj):
    if isinstance(obj, Name):
        return obj.__dict__
    else:
        # Will get into this if the value is not serializable by default 
        # and is also not a Name class object
        return None

def to_dict(input_ordered_dict):
    return loads(dumps(input_ordered_dict, default=custom_serializer))
like image 142
thiruvenkadam Avatar answered Sep 23 '22 05:09

thiruvenkadam


This should work:

import collections

def deep_convert_dict(layer):
    to_ret = layer
    if isinstance(layer, collections.OrderedDict):
        to_ret = dict(layer)

    try:
        for key, value in to_ret.items():
            to_ret[key] = deep_convert_dict(value)
    except AttributeError:
        pass

    return to_ret

Although, as jonrsharpe mentioned, there's probably no reason to do this -- an OrderedDict (by design) works wherever a dict does.

like image 37
Patrick Collins Avatar answered Sep 23 '22 05:09

Patrick Collins