5

I have a this list

a = [OrderedDict([('a','b'), ('c','d'), ('e', OrderedDict([('a','b'), ('c','d') ]))])]

and I want to convert the OrderedDict in dictionary.

Do you know how could I do ?

Thank you !

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

4 Answers4

11

To convert a nested OrderedDict, you could use package json

>>> import json
>>> json.loads(json.dumps(a))

[{'a': 'b', 'c': 'd', 'e': {'a': 'b', 'c': 'd'}}]
Yuan JI
  • 2,927
  • 2
  • 20
  • 29
  • I tried your solution but I have something like this : `{ValueError}dictionary update sequence element #0 has length x; y is required` – Gregory Palmer Jun 07 '19 at 12:30
0

You can build a recursive function to do the conversion from OrderedDict to dict, checking for the datatypes using isinstance calls along the way.

from collections import OrderedDict

def OrderedDict_to_dict(arg):
    if isinstance(arg, (tuple, list)): #for some iterables. might need modifications/additions?
        return [OrderedDict_to_dict(item) for item in arg]

    if isinstance(arg, OrderedDict): #what we are interested in
        arg = dict(arg)

    if isinstance(arg, dict): #next up, iterate through the dictionary for nested conversion
        for key, value in arg.items():
            arg[key] = OrderedDict_to_dict(value)

    return arg

a = [OrderedDict([('a','b'), ('c','d'), ('e', OrderedDict([('a','b'), ('c','d') ]))])]


result = OrderedDict_to_dict(a)
print(result)
#Output:
[{'a': 'b', 'c': 'd', 'e': {'a': 'b', 'c': 'd'}}]

However, note that OrderedDicts are dictionaries too, and support key lookups.

print(a[0]['e'])
#Output:
OrderedDict([('a', 'b'), ('c', 'd')])

a[0]['e']['c']
#Output:
'd'

So, you should not need to convert the OrderedDicts to dicts if you just need to access the values as a dictionary would allow, since OrderedDict supports the same operations.

Paritosh Singh
  • 6,034
  • 2
  • 14
  • 33
0

To convert a nested OrderedDict, you could use For:

from collections import OrderedDict
a = [OrderedDict([('id', 8)]), OrderedDict([('id', 9)])]
data_list = []
for i in a:
    data_list.append(dict(i))
print(data_list)
#Output:[{'id': 8}, {'id': 9}]
0

You should leverage Python's builtin copy mechanism.

You can override copying behavior for OrderedDict via Python's copyreg module (also used by pickle). Then you can use Python's builtin copy.deepcopy() function to perform the conversion.

import copy
import copyreg
from collections import OrderedDict

def convert_nested_ordered_dict(x):
    """
    Perform a deep copy of the given object, but convert
    all internal OrderedDicts to plain dicts along the way.

    Args:
        x: Any pickleable object

    Returns:
        A copy of the input, in which all OrderedDicts contained
        anywhere in the input (as iterable items or attributes, etc.)
        have been converted to plain dicts.
    """
    # Temporarily install a custom pickling function
    # (used by deepcopy) to convert OrderedDict to dict.
    orig_pickler = copyreg.dispatch_table.get(OrderedDict, None)
    copyreg.pickle(
        OrderedDict,
        lambda d: (dict, ([*d.items()],))
    )
    try:
        return copy.deepcopy(x)
    finally:
        # Restore the original OrderedDict pickling function (if any)
        del copyreg.dispatch_table[OrderedDict]
        if orig_pickler:
            copyreg.dispatch_table[OrderedDict] = orig_pickler

Merely by using Python's builtin copying infrastructure, this solution is superior to all other answers presented here, in the following ways:

  • Works for more than just JSON data.

  • Does not require you to implement special logic for each possible element type (e.g. list, tuple, etc.)

  • deepcopy() will properly handle duplicate objects within the collection:

    x = [1,2,3]
    d = {'a': x, 'b': x}
    assert id(d['a']) == id(d['b'])
    
    d2 = copy.deepcopy(d)
    assert id(d2['a']) == id(d2['b'])
    

    Since our solution is based on deepcopy() we'll have the same advantage.

  • This solution also converts attributes that happen to be OrderedDict, not only collection elements:

    class C:
        def __init__(self, a=None, b=None):
            self.a = a or OrderedDict([(1, 'one'), (2, 'two')])
            self.b = b or OrderedDict([(3, 'three'), (4, 'four')])
    
        def __repr__(self):
            return f"C(a={self.a}, b={self.b})"
    
    
    print("original: ", C())
    print("converted:", convert_nested_ordered_dict(C()))
    
    original:  C(a=OrderedDict([(1, 'one'), (2, 'two')]), b=OrderedDict([(3, 'three'), (4, 'four')]))
    converted: C(a={1: 'one', 2: 'two'}, b={3: 'three', 4: 'four'})
    

Demonstration on your sample data:

a = [OrderedDict([('a','b'), ('c','d'), ('e', OrderedDict([('a','b'), ('c','d') ]))])]
b = convert_nested_ordered_dict(a)
print(b)
[{'a': 'b', 'c': 'd', 'e': {'a': 'b', 'c': 'd'}}]
Stuart Berg
  • 17,026
  • 12
  • 67
  • 99