如何将嵌套的OrderedDict转换为dict?

时间:2014-07-31 08:18:54

标签: python dictionary

我有一个嵌套OrderedDict我想转换为dict。在其上应用dict()显然只会转换最后一个条目的最外层。

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))

输出:

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

是否有直接的方法来转换所有出现的情况?

6 个答案:

答案 0 :(得分:23)

最简单的解决方案是使用json转储和加载

from json import loads, dumps
from collections import OrderedDict

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

注意:上面的代码适用于json已知为可序列化对象的字典。可以找到默认对象类型列表here

因此,如果有序字典不包含特殊值,这应该足够了。

编辑:根据评论,让我们改进上面的代码。让我们说,input_ordered_dict可能包含默认情况下json无法序列化的自定义类对象。 在这种情况下,我们应该使用default json.dumps参数和我们的自定义序列化程序。

(例如):

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

此示例可以进一步扩展到更大的范围。我们甚至可以根据需要添加过滤器或修改值。只需将其他部分添加到custom_serializer函数

即可
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

在自定义序列化程序的情况下,顶部给出的函数应该是:

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))

答案 1 :(得分:5)

这应该有效:

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

虽然正如jonrsharpe所说,可能没有理由这样做 - OrderedDict(按设计)可以在dict的任何地方使用。

答案 2 :(得分:2)

注意:这个答案只是部分正确,请查看https://stackoverflow.com/a/25057250/1860929以了解更多关于字母大小相同的原因。

原始答案

这并没有回答转换的问题,更多的是关于需要做什么。

OrderedDict是Dict大小两倍的基本假设是有缺陷的。检查一下:

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

基本上两者都是相同的大小。

但是,操作所用的时间并不相同,事实上,创建一个大字典(使用100-10000个键)比创建具有相同键的OrderedDict快大约7-8倍。 (使用%timeit){/ 1>中的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

因此,IMO,您应该专注于直接将数据读入dict并对其进行操作,而不是先创建OrderedDict,然后重复将其转换为dict。

答案 3 :(得分:0)

我编写了一个递归方法,将OrderedDict转换为简单的字典。

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

注意:OrderedDictdict通常是可以互换的,但在使用assert在两种类型之间运行pytest时遇到了问题。

答案 4 :(得分:0)

这是一个还可以处理列表和元组的版本。在此comment中,OP提到了字典列表也是一种处理情况。

注意,这也会将元组转换为列表。保存元组留给读者练习:)

APP_VERSION: ${APP_VERSION} 
BUILD_NUMBER: ${BUILD_NUMBER}

答案 5 :(得分:0)

此代码应适用于嵌套列表。

def nested_convert_to_dict(input: [dict, collections.OrderedDict]):
    if isinstance(input, collections.OrderedDict):
        res = dict(input)
    else:
        res = input
    try:
        for key, value in res.items():
            res[key] = nested_convert_to_dict(value)
            if isinstance(value, list):
                new_value = []
                for item in value:
                    if isinstance(item, collections.OrderedDict):
                        item = nested_convert_to_dict(item)
                    new_value.append(item)
                res[key] = new_value
    except AttributeError:
        pass
    return res