How to custom-sort a list of dict to use in json.dumps
Since python dicts are unordered collections, use collections.OrderedDict
with a custom sort:
from collections import OrderedDictimport jsonallsites = [ { '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=(',', ': '))
prints:
{ "data": [ { "site": "example1.com", "A1": "G", "A5": "G", "A10": "G" }, { "site": "example2.com", "A1": "G", "A5": "R", "A10": "Y" } ], "Author": "joe"}
In Python3, alecxe's answer no longer works. This should be a comment, but I lack the reputation.
PEP 3113 removed tuple unpacking in function signatures, so the line
allsites_ordered = [OrderedDict(sorted(item.iteritems(), key=lambda (k, v): sort_order.index(k))) for item in allsites]
now has to be
allsites_ordered = [OrderedDict(sorted(item.items(), key=lambda item: sort_order.index(item[0]))) for item in allsites]
or similar. iteritems
has also become just items
.
I had exactly the same problem and devised a lightweight general solution:
from collections import OrderedDictdef 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