2010-12-09 13 views
15

Gibt es in Python 2.6 eine Möglichkeit, einen benutzerdefinierten Schlüssel oder CMP-Funktion zu JSON sort_keys zu liefern?benutzerdefinierte JSON sort_keys Reihenfolge in Python

[ 
    { 
    "key": "numberpuzzles1", 
    "url": "number-puzzle-i.html", 
    "title": "Number Puzzle I", 
    "category": "nestedloops", 
    "points": "60", 
    "n": "087" 
    }, 
    { 
    "key": "gettingindividualdigits", 
    "url": "getting-individual-digits.html", 
    "title": "Getting Individual Digits", 
    "category": "nestedloops", 
    "points": "80", 
    "n": "088" 
    } 
] 

..., die ich in der Liste Variable assigndb gespeichert haben:

Ich habe eine Liste von dicts von JSON kommt wie so bekam. Ich würde gerne in der Lage sein, in die JSON zu laden, zu ändern und serialisiert es wieder mit dumps (oder was auch immer), unter Beibehaltung der Bestellungen der Schlüssel intakt.

Bisher habe ich versucht, so etwas wie dieses:

ordering = {'key': 0, 'url': 1, 'title': 2, 'category': 3, 
      'flags': 4, 'points': 5, 'n': 6} 

def key_func(k): 
    return ordering[k] 

# renumber assignments sequentially 
for (i, a) in enumerate(assigndb): 
    a["n"] = "%03d" % (i+1) 

s = json.dumps(assigndb, indent=2, sort_keys=True, key=key_func) 

... aber natürlich dumps unterstützt nicht einen benutzerdefinierten Schlüssel wie list.sort() tut. Etwas mit einer benutzerdefinierten JSONEncoder vielleicht? Ich kann es nicht in Gang bringen.

Antwort

4

Diese Art von hässlich ist, aber im Falle tokland-Lösung ist für Sie nicht:

data = [{'category': 'nestedloops', 'title': 'Number Puzzle I', 'url': 'number-puzzle-i.html', 'n': '087', 'points': '60', 'key': 'numberpuzzles1'}, {'category': 'nestedloops', 'title': 'Getting Individual Digits', 'url': 'getting-individual-digits.html', 'n': '088', 'points': '80', 'key': 'gettingindividualdigits'}] 
ordering = {'key': 0, 'url': 1, 'title': 2, 'category': 3, 
      'flags': 4, 'points': 5, 'n': 6} 
outlist = [] 
for d in data: 
    outlist.append([]) 
    for k in sorted(d.keys(), key=lambda k: ordering[k]): 
     outlist[-1].append(json.dumps({k: d[k]})) 

for i, l in enumerate(outlist): 
    outlist[i] = "{" + ",".join((s[1:-1] for s in outlist[i])) + "}" 

s = "[" + ",".join(outlist) + "]" 
+0

Hässlich, aber funktional; Vielen Dank! –

12

Eine Idee (getestet mit 2.7):

import json 
import collections 
json.encoder.c_make_encoder = None 
d = collections.OrderedDict([("b", 2), ("a", 1)]) 
json.dumps(d) 
# '{"b": 2, "a": 1}' 

Siehe auch: OrderedDict + issue6105. Der Hack c_make_encoder scheint nur für Python 2.x benötigt zu werden. Keine direkte Lösung, weil Sie dict s für s ändern müssen, aber es kann noch verwendbar sein. Ich überprüfte die json-Bibliothek (encode.py) und das bestellte ist hartcodiert:

if _sort_keys: 
    items = sorted(dct.items(), key=lambda kv: kv[0]) 
+1

Diese _might_ Arbeit, aber die dicts kommen aus JSON zunächst, und so die Tasten sind bereits ungeordnet. –

+0

Meh. OrderedDict ist nur 2.7. –

+0

@Graham: Unabhängig von der Python-Version gibt es mehrere Module, die geordnete Dicts implementieren, wählen Sie eine von ihnen. – tokland

-1

Dank. Ich musste einen Zeitstempel-Schlüssel: Wert an der Spitze meines JSON-Objekts, egal was. Offensichtlich hat das Sortieren der Schlüssel dies verschärft, da es mit "t" beginnt.

so etwas wie dies verwendet, während den Zeitstempel Schlüssel in der dict_data setzen arbeiteten sofort:

d = collections.OrderedDict(dict_data) 
0

Ich hatte das gleiche Problem und collections.OrderedDict war einfach nicht für die Aufgabe geeignet, da es alles alphabetisch geordnet. Also schrieb ich etwas Ähnliches wie Andrew Clark Lösung:

def json_dumps_sorted(data, **kwargs): 
    sorted_keys = kwargs.get('sorted_keys', tuple()) 
    if not sorted_keys: 
     return json.dumps(data) 
    else: 
     out_list = [] 
     for element in data: 
      element_list = [] 
      for key in sorted_keys: 
       if key in element: 
        element_list.append(json.dumps({key: element[key]})) 
      out_list.append('{{{}}}'.format(','.join((s[1:-1] for s in element_list)))) 
     return '[{}]'.format(','.join(out_list)) 

Sie es wie folgt verwendet werden:

json_string = json_dumps_sorted([ 
    { 
     "key": "numberpuzzles1", 
     "url": "number-puzzle-i.html", 
     "title": "Number Puzzle I", 
     "category": "nestedloops", 
     "points": "60", 
     "n": "087" 
    }, { 
     "key": "gettingindividualdigits", 
     "url": "getting-individual-digits.html", 
     "title": "Getting Individual Digits", 
     "category": "nestedloops", 
     "points": "80", 
     "n": "088" 
    } 
], sorted_keys=(
    'key', 
    'url', 
    'title', 
    'category', 
    'flags', 
    'points', 
    'n' 
)) 
Verwandte Themen