如何自定义排序要在 json.dumps 中使用的 dict 列表

Posted

技术标签:

【中文标题】如何自定义排序要在 json.dumps 中使用的 dict 列表【英文标题】:How to custom-sort a list of dict to use in json.dumps 【发布时间】:2013-09-23 03:40:15 【问题描述】:

我有一个类似的列表

allsites = [
    
        'A5': 'G', 
        'A10': 'G', 
        'site': 'example1.com', 
        'A1': 'G'
    , 
    
        'A5': 'R', 
        'A10': 'Y',
        'site': 'example2.com', 
        'A1': 'G'
    
]

我在json.dumps 中使用:

data =  'Author':"joe", 'data':allsites 
print json.dumps(data,sort_keys=True,indent=4, separators=(',', ': '))

这会输出以下 JSON:


    "Author": "joe",
    "data": [
        
            "A1": "G",
            "A10": "G",
            "A5": "G",
            "site": "example1.com"
        ,
        
            "A1": "G",
    (...)

我希望这个 JSON 字符串的“数据”部分通过自定义键(“字母”)进行排序,在上述情况下,这将是 site, A1, A5, A10,实际上看起来像:


    "Author": "joe",
    "data": [
        
            "site": "example1.com",
            "A1": "G",
            "A5": "G",
            "A10": "G"
        ,
        
            "site": "example2.com",
            "A1": "G",
    (...)

我在Sorting FAQ 中了解了自定义排序,但它只是提供了一种覆盖比较函数的方法,更不用说我不知道​​如何将其插入到我的代码中。

怎么做?

【问题讨论】:

【参考方案1】:

由于 python dicts 是无序的集合,请使用 collections.OrderedDict 和自定义排序:

from collections import OrderedDict
import json

allsites = [
    
        'A5': 'G',
        'A10': 'G',
        'site': 'example1.com',
        'A1': 'G'
    ,
    
        'A5': 'R',
        'A10': 'Y',
        'site': 'example2.com',
        'A1': 'G'
    
]

sort_order = ['site', 'A1', 'A5', 'A10']
allsites_ordered = [OrderedDict(sorted(item.iteritems(), key=lambda (k, v): sort_order.index(k)))
                    for item in allsites]

data = 'Author': "joe", 'data': allsites_ordered
print json.dumps(data, indent=4, separators=(',', ': '))

打印:


    "data": [
        
            "site": "example1.com",
            "A1": "G",
            "A5": "G",
            "A10": "G"
        ,
        
            "site": "example2.com",
            "A1": "G",
            "A5": "R",
            "A10": "Y"
        
    ],
    "Author": "joe"

【讨论】:

不要为 python3 工作更多,@alecxe,它说:“python 3 不支持元组参数解包”。见斯科特答案。【参考方案2】:

在 Python3 中,alecxe 的答案不再有效。这应该是评论,但我缺乏声誉。

PEP 3113 删除了函数签名中的元组解包,所以行

allsites_ordered = [OrderedDict(sorted(item.iteritems(), key=lambda (k, v): sort_order.index(k)))
                    for item in allsites]

现在必须是

allsites_ordered = [OrderedDict(sorted(item.items(), key=lambda item: sort_order.index(item[0])))
                    for item in allsites]

或类似的。 iteritems 也变成了 items

【讨论】:

在 Python 3.6 中,dict 现在是默认排序的。也就是说,它可以工作,而且我们不应该“计划让它工作”。 @CharlesMerriam 同意。目前字典排序有点荒谬。我想,最大的问题是该语言的非 CPython 实现可能还没有“把事情整理好”。 小更新:从 Python 3.7 开始,dict 是默认排序的,我们可以指望它——它已成为规范的一部分。对于使用 OrderedDict 作为您正在使用 ordering 属性的语义指示符,仍然存在争议。此外,OrderedDict 保留了内置的dict 仍然缺少的额外的popitem()move_to_end() 方法。此答案中的更多详细信息:***.com/a/50872567/600882【参考方案3】:

我遇到了完全相同的问题,并设计了一个轻量级的通用解决方案:

from collections import OrderedDict

def make_custom_sort(orders):
    orders = [k: -i for (i, k) in enumerate(reversed(order), 1) for order in orders]
    def process(stuff):
        if isinstance(stuff, dict):
            l = [(k, process(v)) for (k, v) in stuff.items()]
            keys = set(stuff)
            for order in orders:
                if keys.issuperset(order):
                    return OrderedDict(sorted(l, key=lambda x: order.get(x[0], 0)))
            return OrderedDict(sorted(l))
        if isinstance(stuff, list):
            return [process(x) for x in stuff]
        return stuff
    return process

首先,您创建一个自定义排序函数的实例:

custom_sort = make_custom_sort([ ["site", "A1", "A5", "A10"] ])

现在,实际排序:

result = custom_sort(allsites)

...您可以将其转储为 JSON 对象:

print json.dumps(result, indent=4)

结果

[
    
        "site": "example1.com", 
        "A1": "G", 
        "A5": "G", 
        "A10": "G"
    , 
    
        "site": "example2.com", 
        "A1": "G", 
        "A5": "R", 
        "A10": "Y"
    
]

更多

闭包是递归的。如双括号所示,您可以指定嵌套在结构中的各种字典所需的排序顺序。

GitHub 上的项目:https://github.com/laowantong/customsort

【讨论】:

以上是关于如何自定义排序要在 json.dumps 中使用的 dict 列表的主要内容,如果未能解决你的问题,请参考以下文章

由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

json.dumps参数之解

猴子补丁(monkey patch)

如何在 Python 中使用 json.dumps() 将整数打印为十六进制字符串

如何摆脱 Python json.dumps 中的“quot”

帝国cms统计使用自定义字段的数量并按照统计的多少进行排序