假设
orig
是一个 OrderedDict
,其中包含普通的字符串:字符串键值对,但有时该值可能是另一个嵌套的 OrderedDict
。
我想按键按字母顺序(升序)对
orig
进行排序,然后递归地进行排序。
规则:
需要
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)
@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())}
另请参阅 https://mail.python.org/pipermail/python-dev/2016-September/146327.html 有关 python 有序字典实现的详细信息。另外,声明这将是 python 3.7 的语言功能:https://mail.python.org/pipermail/python-dev/2017-December/151283.html
编辑:对于 python 3.6+,@pelson 的 answer 更好
类似:
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
我在获取稳定对象时遇到了非常类似的问题,这样我就可以获得稳定的哈希值,但我的对象混合了列表和字典,所以我必须对所有字典进行排序,深度优先,然后对列表进行排序。这扩展了 @acushner 的 answer:
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+ 中排序)。对于稳定哈希的情况,这不是必需的。
与@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)
@pelson 的答案和@cjbarth 的答案的组合,带有
key
和 reverse
参数:
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
如果你仍然生活在 py2...像我一样...这是 3.6+ 版本,带有 lambda 来对键进行预排序。
def __sort_od(od):
res = OrderedDict()
for k, v in sorted(od.items(), key=lambda k: k[0]):
if isinstance(v, dict):
res[k] = __sort_od(v)
else:
res[k] = v
return res
sorted_OrderedDict = __sort_od(unsorted_dict)