【问题标题】:How to get sorted list inside a dictionary with json.dumps()如何使用 json.dumps() 在字典中获取排序列表
【发布时间】:2014-07-27 10:17:31
【问题描述】:

我有以下问题:有一个如下的 python 字典:

{"qqq": [{"bbb": "111"}, {"aaa": "333"}], "zzz": {"bbb": [5, 2, 1, 9]}}

我想获取一个有序的json对象比如:

'{"qqq": [{"aaa": "333"}, {"bbb": "111"}], "zzz": {"bbb": [1, 2, 5, 9]}}'

目前我使用以下内容:

class ListEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, list):
            return sorted(o)
        return json.JSONEncoder.default(self, o)

print json.dumps(c, sort_keys=True, cls=ListEncoder)

但是我的对象内的两个列表没有排序,我得到:

'{"qqq": [{"bbb": "111"}, {"aaa": "333"}], "zzz": {"bbb": [5, 2, 1, 9]}}'

可能是因为自定义的 JSONEncoder 跳过了一个已经知道如何管理的类型(列表)。

更新

下面的Martijn解决方案非常适合上面的例子,但不幸的是我必须管理更复杂的字典,深度更大:例如以下两个

a = {
    'aaa': 'aaa',
    'op': 'ccc',
    'oppa': {
        'ggg': [{'fff': 'ev'}],
        'flt': {
            'nnn': [
                {
                'mmm': [{'a_b_d': [6]},{'a_b_c': [6,7]}]
                },
                {
                    'iii': [3, 2, 4, 5]
                }
            ]
        }
    },
    'rrr': {},
    'ttt': ['aaa-bbb-ccc']
}
b = {
    'aaa': 'aaa',
    'op': 'ccc',
    'oppa': {
        'ggg': [{'fff': 'ev'}],
        'flt': {
            'nnn': [
                {
                    'iii': [2, 3, 4, 5]
                },
                {
                'mmm': [{'a_b_c': [6,7]},{'a_b_d': [6]}]
                }
            ]
        }
    },
    'rrr': {},
    'ttt': ['aaa-bbb-ccc']
}

如果对同一内部的列表进行排序,它们将是相同的。 但它们不在上面的类中,我得到了 2 个不同的 json 字符串:

{"aaa": "aaa", "op": "ccc", "oppa": {"flt": {"nnn": [{"iii": [3, 2, 4, 1]}, {"mmm": [{"a_b_d": [6]}, {"a_b_c": [6, 7]}]}]}, "ggg": [{"fff": "ev"}]}, "rrr": {}, "ttt": ["aaa-bbb-ccc"]}
{"aaa": "aaa", "op": "ccc", "oppa": {"flt": {"nnn": [{"iii": [2, 3, 4, 5]}, {"mmm": [{"a_b_c": [6, 7]}, {"a_b_d": [6]}]}]}, "ggg": [{"fff": "ev"}]}, "rrr": {}, "ttt": ["aaa-bbb-ccc"]}

有办法解决这个问题吗?

【问题讨论】:

    标签: python json list dictionary


    【解决方案1】:

    default 不用于列表;该方法仅适用于编码器不知道如何处理的类型。改写 encode 方法:

    class SortedListEncoder(json.JSONEncoder):
        def encode(self, obj):
            def sort_lists(item):
                if isinstance(item, list):
                    return sorted(sort_lists(i) for i in item)
                elif isinstance(item, dict):
                    return {k: sort_lists(v) for k, v in item.items()}
                else:
                    return item
            return super(SortedListEncoder, self).encode(sort_lists(obj))
    

    这实际上只是在编码之前(递归地)对所有列表进行排序;这可以在将它传递给json.dumps() 之前完成,但这样它是编码器的一部分责任,就像对键进行排序一样。

    演示:

    >>> json.dumps(c, sort_keys=True, cls=SortedListEncoder)
    '{"qqq": [{"aaa": "333"}, {"bbb": "111"}], "zzz": {"bbb": [1, 2, 5, 9]}}'
    >>> json.dumps(a, sort_keys=True, cls=SortedListEncoder)
    '{"aaa": "aaa", "op": "ccc", "oppa": {"flt": {"nnn": [{"iii": [2, 3, 4, 5]}, {"mmm": [{"a_b_c": [6, 7]}, {"a_b_d": [6]}]}]}, "ggg": [{"fff": "ev"}]}, "rrr": {}, "ttt": ["aaa-bbb-ccc"]}'
    >>> json.dumps(b, sort_keys=True, cls=SortedListEncoder)
    '{"aaa": "aaa", "op": "ccc", "oppa": {"flt": {"nnn": [{"iii": [2, 3, 4, 5]}, {"mmm": [{"a_b_c": [6, 7]}, {"a_b_d": [6]}]}]}, "ggg": [{"fff": "ev"}]}, "rrr": {}, "ttt": ["aaa-bbb-ccc"]}'
    

    【讨论】:

    • 从风格的角度来看,排序列表确实应该在编码器之外完成。作为一种数据结构,列表是有序的。字典键通常以任意顺序返回,sort_keys 只是以特定顺序返回它们而不更改基础数据。也许这里更好的选择是将列表存储为集合并为集合编写编码器。
    【解决方案2】:

    我把这个留在这里是因为我遇到了同样的问题。

    您可以使用此函数对嵌套数据结构进行排序:

    def sort_data(data):
        if isinstance(data, dict):
            output = OrderedDict()
            for key, value in data.items():
                output[key] = sort_data(value)
            return output
        elif isinstance(data, list):
            calculated = [sort_data(x) for x in data]
            return sorted(calculated, key=str)
        elif isinstance(data, (int, bool, str, float, type(None))):
            return data
        else:
            raise Exception("Unkown type: {} for {}".format(type(data), data))
    

    例子:

    data = {"b":[ "zzz", "yyy", "xxx"],
            "d": [42, 54, 675, "aaa"],
            "c": {"a": ["bbb", "ccc", "aaa"]},
            }
    
    sorted_data = sort_data(data)
    print(json.dumps(sorted_data, indent=2, sort_keys=True))
    
    # prints:
    #{
    #    "b": [
    #        "xxx",
    #        "yyy",
    #        "zzz"
    #    ],
    #    "c": {
    #        "a": [
    #            "aaa",
    #            "bbb",
    #            "ccc"
    #        ]
    #    },
    #    "d": [
    #        42,
    #        54,
    #        675,
    #        "aaa"
    #    ]
    #}
    
    

    【讨论】:

      猜你喜欢
      • 2013-09-23
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2021-11-10
      • 2018-09-03
      • 2020-03-26
      • 1970-01-01
      • 2011-09-23
      相关资源
      最近更新 更多