16

Sayorig是一个OrderedDict包含普通 string:string 键值对的值,但有时该值可能是另一个嵌套的值OrderedDict

我想orig按字母顺序(升序)按键排序,然后递归地进行。

规则:

  • 假设键字符串是不可预测的
  • 假设嵌套可以无限进行,例如级别 1-50 都有字符串、OrderedDicts 等作为值。

需要sorted算法帮助:

import string
from random import choice


orig = OrderedDict((
    ('a', choice(string.digits)),
    ('b', choice(string.digits)),
    ('c', choice(string.digits)),
    ('special', OrderedDict((
        ('a', choice(string.digits)),
        ('b', choice(string.digits)),
        ('c', choice(string.digits)),
    )))
))

sorted_copy = OrderedDict(sorted(orig.iteritems(), ...))

self.assertEqual(orig, sorted_copy)
4

5 回答 5

23

编辑:对于 python 3.6+,@pelson 的答案更好

就像是:

def sortOD(od):
    res = OrderedDict()
    for k, v in sorted(od.items()):
        if isinstance(v, dict):
            res[k] = sortOD(v)
        else:
            res[k] = v
    return res
于 2014-03-28T19:36:37.437 回答
18

@acushner 的解决方案现在可以在 python3.6+ 中简化,因为字典现在保留了它们的插入顺序。

鉴于我们现在可以使用标准字典,代码现在看起来像:

def order_dict(dictionary):
    result = {}
    for k, v in sorted(dictionary.items()):
        if isinstance(v, dict):
            result[k] = order_dict(v)
        else:
            result[k] = v
    return result

因为我们可以使用标准字典,我们也可以使用标准字典推导,所以代码归结为:

def order_dict(dictionary):
    return {k: order_dict(v) if isinstance(v, dict) else v
            for k, v in sorted(dictionary.items())}

有关python 有序字典实现的详细信息,另请参见https://mail.python.org/pipermail/python-dev/2016-September/146327.html 。此外,声明这将是 python 3.7 的语言功能:https ://mail.python.org/pipermail/python-dev/2017-December/151283.html

于 2017-12-19T08:00:17.740 回答
9

我在获得一个稳定的对象时遇到了一个非常相似的问题,所以我可以获得一个稳定的哈希,除了我的对象混合了列表和字典,所以我必须对所有字典进行排序,首先是深度,然后对列表进行排序。这扩展了@acushner答案

def deep_sort(obj):
    if isinstance(obj, dict):
        obj = OrderedDict(sorted(obj.items()))
        for k, v in obj.items():
            if isinstance(v, dict) or isinstance(v, list):
                obj[k] = deep_sort(v)

    if isinstance(obj, list):
        for i, v in enumerate(obj):
            if isinstance(v, dict) or isinstance(v, list):
                obj[i] = deep_sort(v)
        obj = sorted(obj, key=lambda x: json.dumps(x))

    return obj

顺便说一句,如果您发现自己的对象中有需要排序的类,您可以对jsonpickle.dumps()它们进行排序,然后json.loads()是它们,然后deep_sort()是它们。json.dumps()如果这很重要,那么您总是jsonpickle.loads()可以回到您开始的地方,除了排序(好吧,仅在 Python 3.6+ 中排序)。对于稳定哈希的情况,这不是必需的。

于 2019-12-06T18:41:47.837 回答
5

与@acushner 的解决方案非常相似,但基于类:

from collections import OrderedDict


class SortedDict(OrderedDict):

    def __init__(self, **kwargs):
        super(SortedDict, self).__init__()

        for key, value in sorted(kwargs.items()):
            if isinstance(value, dict):
                self[key] = SortedDict(**value)
            else:
                self[key] = value

用法:

sorted_dict = SortedDict(**unsorted_dict)
于 2015-07-17T20:00:59.317 回答
0

@pelson's answer@cjbarth's answer的组合,带有keyreverse参数:

def deep_sorted(obj, *, key=None, reverse=False):
    if isinstance(obj, dict):
        return {k: deep_sorted(v, key=key, reverse=reverse) for k, v in sorted(obj.items(), key=key, reverse=reverse)}
    if isinstance(obj, list):
        return [deep_sorted(v, key=key, reverse=reverse) for i, v in sorted(enumerate(obj), key=key, reverse=reverse)]
    return obj
于 2021-11-03T19:57:04.510 回答