147

I am struggling with the following problem: I want to convert an OrderedDict like this:

OrderedDict([('method', 'constant'), ('data', '1.225')])

into a regular dict like this:

{'method': 'constant', 'data':1.225}

because I have to store it as string in a database. After the conversion the order is not important anymore, so I can spare the ordered feature anyway.

Thanks for any hint or solutions,

Ben

iruvar
  • 22,736
  • 7
  • 53
  • 82
Ben A.
  • 1,511
  • 2
  • 11
  • 8

9 Answers9

139
>>> from collections import OrderedDict
>>> OrderedDict([('method', 'constant'), ('data', '1.225')])
OrderedDict([('method', 'constant'), ('data', '1.225')])
>>> dict(OrderedDict([('method', 'constant'), ('data', '1.225')]))
{'data': '1.225', 'method': 'constant'}
>>>

However, to store it in a database it'd be much better to convert it to a format such as JSON or Pickle. With Pickle you even preserve the order!

ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • 6
    you can [preserve order with `json` too](http://stackoverflow.com/q/6921699/4279). – jfs Nov 23 '13 at 19:59
  • Thanks, and also for the advice using pickle. I would use pickle and I actually do it in other places, but some constraints demand using a dict converted to string. – Ben A. Nov 23 '13 at 20:00
  • Would converting ordereddict to dict loose order? – RamPrasadBismil Feb 06 '16 at 04:06
  • 2
    Yes it does lose order. – nael Jun 01 '16 at 21:21
  • json.loads also in python < 3.0 does not preserve the order. – nael Jun 01 '16 at 22:55
  • 3
    Please note that thos does not work for nested OrderedDictionary data, @thiruvenkadam should be the accepted answer. – Micheal J. Roberts Feb 24 '20 at 13:17
  • @WindUpLordVexxos I disagree, the OP's data wasn't nested, so this answers his question. And going through JSON for this purpose isn't very efficient... – ThiefMaster Feb 24 '20 at 13:20
  • @ThiefMaster Your method works. But for the OPs data. I'd argue that the structure outlined in his question could have been a dummy example, and that we can't assume that anyone reading this question would have his exact same structure. When answering these questions, we must assume a generalistic stance agnostic of the OPs specifics. – Micheal J. Roberts Feb 24 '20 at 13:23
100

Even though this is a year old question, I would like to say that using dict will not help if you have an ordered dict within the ordered dict. The simplest way that could convert those recursive ordered dict will be

import json
from collections import OrderedDict
input_dict = OrderedDict([('method', 'constant'), ('recursive', OrderedDict([('m', 'c')]))])
output_dict = json.loads(json.dumps(input_dict))
print output_dict
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
thiruvenkadam
  • 4,170
  • 4
  • 27
  • 26
  • 8
    Nice move for a script etc., i.e. _I don't care about performance for this one-off task, just gimme dicts so I can pretty print them_ – floer32 Apr 10 '16 at 17:10
10

It is easy to convert your OrderedDict to a regular Dict like this:

dict(OrderedDict([('method', 'constant'), ('data', '1.225')]))

If you have to store it as a string in your database, using JSON is the way to go. That is also quite simple, and you don't even have to worry about converting to a regular dict:

import json
d = OrderedDict([('method', 'constant'), ('data', '1.225')])
dString = json.dumps(d)

Or dump the data directly to a file:

with open('outFile.txt','w') as o:
    json.dump(d, o)
Kyle Neary
  • 889
  • 6
  • 7
7

If you are looking for a recursive version without using the json module:

def ordereddict_to_dict(value):
    for k, v in value.items():
        if isinstance(v, dict):
            value[k] = ordereddict_to_dict(v)
    return dict(value)
spg
  • 9,309
  • 4
  • 36
  • 41
5

Here is what seems simplest and works in python 3.7

from collections import OrderedDict

d = OrderedDict([('method', 'constant'), ('data', '1.225')])
d2 = dict(d)  # Now a normal dict

Now to check this:

>>> type(d2)
<class 'dict'>
>>> isinstance(d2, OrderedDict)
False
>>> isinstance(d2, dict)
True

NOTE: This also works, and gives same result -

>>> {**d}
{'method': 'constant', 'data': '1.225'}
>>> {**d} == d2
True

As well as this -

>>> dict(d)
{'method': 'constant', 'data': '1.225'}
>>> dict(d) == {**d}
True

Cheers

radtek
  • 34,210
  • 11
  • 144
  • 111
4

You can use "dict_constructor" parameters.

xmltodict.parse(text, attr_prefix='',dict_constructor=dict)

greybeard
  • 2,249
  • 8
  • 30
  • 66
CoInz
  • 41
  • 1
0

If your data structure might contain internal (nested) OrderedDict instances, 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 arbitrary data hierarchies, including nested OrderedDicts.

  • 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 d['a'] is d['b']
    
    d2 = copy.deepcopy(d)
    assert d2['a'] is 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):
            self.a = a
    
        def __repr__(self):
            return f"C(a={self.a})"
    
    c = C(OrderedDict([(1, 'one'), (2, 'two')]))
    print("original: ", c)
    print("converted:", convert_nested_ordered_dict(c))
    
    original:  C(a=OrderedDict([(1, 'one'), (2, 'two')]))
    converted: C(a={1: 'one', 2: 'two'})
    
Stuart Berg
  • 17,026
  • 12
  • 67
  • 99
-2

Its simple way

>>import json 
>>from collection import OrderedDict

>>json.dumps(dict(OrderedDict([('method', 'constant'), ('data', '1.225')])))
Ramesh K
  • 282
  • 4
  • 13
-2

A version that handles nested dictionaries and iterables but does not use the json module. Nested dictionaries become dict, nested iterables become list, everything else is returned unchanged (including dictionary keys and strings/bytes/bytearrays).

def recursive_to_dict(obj):
    try:
        if hasattr(obj, "split"):    # is string-like
            return obj
        elif hasattr(obj, "items"):  # is dict-like
            return {k: recursive_to_dict(v) for k, v in obj.items()}
        else:                        # is iterable
            return [recursive_to_dict(e) for e in obj]
    except TypeError:                # return everything else
        return obj
E_net4
  • 27,810
  • 13
  • 101
  • 139
Eponymous
  • 6,143
  • 4
  • 43
  • 43