加载JSON时保留订单并维护所有密钥?

时间:2016-10-31 01:11:34

标签: python python-2.7 dictionary ordereddictionary defaultdict

使用here描述的方法,我在加载嵌套的JSON文件时将OrderedDict作为object_pairs_hook传递,以保留顺序。

保留订单,这对于JSON对象的大多数来说都很好。但是JSON的一部分(在嵌套的最低级别),看起来像:

"In Content" : { "Sulvo" : "abc.com_336x280_he-inlinecontentmobile", "Sulvo" : "abc.com_336x280_he-inlinecontentmobile_level2", "Sulvo" : "abc.com_336x280_he-inlinecontentmobile_level3", "Adsense" : "" },

处理后,只保留其中一个相同的键:

OrderedDict([(u'Sulvo', u'homeepiphany.com_336x280_he-inlinecontentmobile_level3'), (u'Adsense', u'')])),

我知道我们可以拥有一个字典,该字典包含具有defaultdict的相同键名的多个项目。以下不起作用,即使它确实如此,我认为我们会获得钥匙但却失去了订单,所以我们不会更好:

j = json.load(open('he.json'), object_pairs_hook=defaultdict)

是否可以一次性维护订单 AND 保留所有密钥?

Python 2.7.12

1 个答案:

答案 0 :(得分:3)

如果查看docs for json.load,它们会概述object_pairs_hook参数的作用:

  

object_pairs_hook是一个可选函数,将使用对有序列表对解码的任何对象文字的结果进行调用。将使用object_pairs_hook的返回值代替dict

您需要做的就是编写一个函数,在给定(key, value)对列表的情况下,构造您的对象。

一种方法是什么也不做,只是直接传递项目列表而不构建字典:

def handle_mapping(items):
    return items

然后,你的JSON解析如下:

[(u'In Content',
  [(u'Sulvo', u'abc.com_336x280_he-inlinecontentmobile'),
   (u'Sulvo', u'abc.com_336x280_he-inlinecontentmobile_level2'),
   (u'Sulvo', u'abc.com_336x280_he-inlinecontentmobile_level3'),
   (u'Adsense', u'')])]

如果您确实要将重复键的值合并到列表中,可以使用OrderedDict

def handle_mapping(items):
    d = OrderedDict()
    duplicate_keys = set()

    for key, value in items:
        # So [('k', 'v')] becomes {'k': 'v'}
        if key not in d:
            d[key] = value
        else:
            # So [('k', 'v1'), ('k', 'v2')] becomes {'k': ['v1', 'v2']}
            if key not in duplicate_keys:
                duplicate_keys.add(key)
                d[key] = [d[key]]

            d[key].append(value)

    return d

然后,您将对象解析为:

OrderedDict([(u'In Content',
              OrderedDict([(u'Sulvo',
                            [u'abc.com_336x280_he-inlinecontentmobile',
                             u'abc.com_336x280_he-inlinecontentmobile_level2',
                             u'abc.com_336x280_he-inlinecontentmobile_level3']),
                           (u'Adsense', u'')]))])