How to convert a nested OrderedDict to a dict?

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

 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 intros?

+14
python dictionary
Jul 31 '14 at 8:18
source share
5 answers

The easiest solution is to use JSON dumps and downloads.

 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 by json as serializable objects. A list of default object types can be found here.

So, this should be enough if the ordered dictionary does not contain special meanings.

EDIT: Based on the comments, let's improve the code above. Suppose input_ordered_dict may contain custom class objects that cannot be serialized by json by default. In this scenario, we should use the json.dumps default parameter with the json.dumps native serializer.

(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 to a much larger area. We can even add filters or change the value of our need. Just add another 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 listed above, in the 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)) 
+27
Dec 09 '14 at 6:54
source share

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 is no reason for this - OrderedDict (by design) works wherever the dict does.

+6
Jul 31 '14 at 8:24
source share

NOTE This answer is only partly correct, check out https://stackoverflow.com/a/126298/129 to find out more about why dicts are the same size.

Original answer

This does not answer the question of conversion, but more about what needs to be done.

The basic assumption that an OrderedDict is twice the size of a Dict is erroneous. Check this:

 import sys import random from collections import OrderedDict test_dict = {} test_ordered_dict = OrderedDict() for key in range(10000): test_dict[key] = random.random() test_ordered_dict[key] = random.random() sys.getsizeof(test_dict) 786712 sys.getsizeof(test_ordered_dict) 786712 

Basically, both are the same size.

However, the time spent on operations is not the same, and in fact, creating a large dictionary (with 100-10000 keys) is about 7-8 times faster than creating an OrderedDict with the same keys. (Tested with %timeit in ipython )

 import sys import random from collections import OrderedDict def operate_on_dict(r): test_dict = {} for key in range(r): test_dict[key] = random.random() def operate_on_ordered_dict(r): test_ordered_dict = OrderedDict() for key in range(r): test_ordered_dict[key] = random.random() %timeit for x in range(100): operate_on_ordered_dict(100) 100 loops, best of 3: 9.24 ms per loop %timeit for x in range(100): operate_on_dict(100) 1000 loops, best of 3: 1.23 ms per loop 

So IMO, you should focus on reading the data directly in the dict and work on it, rather than creating an OrderedDict first and then converting it to a dict again.

+2
Jul 31 '14 at 9:32
source share

I wrote a recursive method to convert OrderedDict to a simple dict.

 def recursive_ordered_dict_to_dict(ordered_dict): simple_dict = {} for key, value in ordered_dict.items(): if isinstance(value, OrderedDict): simple_dict[key] = recursive_ordered_dict_to_dict(value) else: simple_dict[key] = value return simple_dict 

Note: OrderedDict and dict are usually interchangeable, but I ran into a problem when doing an assert between two types using pytest .

0
May 16 '18 at 21:08
source share

Here's a version that also handles lists and tuples. In this comment, FP mentions that dictation lists also make sense.

Note that this also converts tuples to lists. Saving tuples is left as an exercise for the reader :)

 def od2d(val): if isinstance(val, (OrderedDict, dict)): return {k: od2d(v) for k, v in val.items()} elif isinstance(val, (tuple, list)): return [od2d(v) for v in val] else: return val 
0
Jun 07 '19 at 3:12
source share



All Articles