23

我有一个类似的列表

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

我在 a 中使用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",
    (...)

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

怎么做?

4

3 回答 3

29

由于 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"
}
于 2013-09-18T11:48:24.293 回答
16

在 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

于 2016-06-29T19:03:27.600 回答
6

I had exactly the same problem and devised a lightweight general solution:

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

First, you create an instance of a custom-order sorting function:

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

Now, the actual sorting:

result = custom_sort(allsites)

... which you may dump as a JSON object:

print json.dumps(result, indent=4)

Result

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

More

The closure is recursive. As indicated by the double brackets, you could specify as many sort orders as the various dictionaries nested in your structure would require.

Project on GitHub: https://github.com/laowantong/customsort

于 2014-07-29T15:48:40.263 回答