JSONオブジェクトのアイテムは、「json.dumps」を使用して順序が狂っていますか?


156

私はjson.dumpsjsonに変換するために使用しています

countries.append({"id":row.id,"name":row.name,"timezone":row.timezone})
print json.dumps(countries)

私が持っている結果は:

[
   {"timezone": 4, "id": 1, "name": "Mauritius"}, 
   {"timezone": 2, "id": 2, "name": "France"}, 
   {"timezone": 1, "id": 3, "name": "England"}, 
   {"timezone": -4, "id": 4, "name": "USA"}
]

キーをID、名前、タイムゾーンの順にしたいのですが、代わりにタイムゾーン、ID、名前を持っています。

どうすれば修正できますか?

回答:


243

Python dict(Python 3.7より前)とJSONオブジェクトはどちらも順序付けられていないコレクションです。sort_keysパラメータを渡して、キーを並べ替えることができます。

>>> import json
>>> json.dumps({'a': 1, 'b': 2})
'{"b": 2, "a": 1}'
>>> json.dumps({'a': 1, 'b': 2}, sort_keys=True)
'{"a": 1, "b": 2}'

特定の注文が必要な場合; あなたが使うcollections.OrderedDictことができます

>>> from collections import OrderedDict
>>> json.dumps(OrderedDict([("a", 1), ("b", 2)]))
'{"a": 1, "b": 2}'
>>> json.dumps(OrderedDict([("b", 2), ("a", 1)]))
'{"b": 2, "a": 1}'

Python 3.6以降、キーワード引数の順序は保持され、上記はより良い構文を使用して書き換えることができます。

>>> json.dumps(OrderedDict(a=1, b=2))
'{"a": 1, "b": 2}'
>>> json.dumps(OrderedDict(b=2, a=1))
'{"b": 2, "a": 1}'

PEP 468 – Preserving Keyword Argument Orderを参照してください。

あなたの入力はJSONとして指定されている場合は、(取得する順序を保持するためにOrderedDict)、あなたが渡すことができobject_pair_hook@Fred Yankowskiによって示唆されているように

>>> json.loads('{"a": 1, "b": 2}', object_pairs_hook=OrderedDict)
OrderedDict([('a', 1), ('b', 2)])
>>> json.loads('{"b": 2, "a": 1}', object_pairs_hook=OrderedDict)
OrderedDict([('b', 2), ('a', 1)])

2
OrderedDictのinitは本当に醜い
jean

3
@jean:初期値はとは何の関係もありませんOrderedDict()、あなたが渡すことができますdictOrderedDict()、あなたが順序対のリストを渡すことができますdict()あまりにも-順序は、これらの例の両方で失われているが。
jfs 2015

注文を保存するときに初期化することを意味し、 '('と ')'を何度も入力する必要があります
jean


25
また、を使用してJSONをロードするd = json.load(f, object_pairs_hook=OrderedDict)と、後でjson.dump(d)元の要素の順序が保持されます。
Fred Yankowski、2016年

21

他の人が述べているように、根本的なdictは順序付けられていません。ただし、PythonにはOrderedDictオブジェクトがあります。(これらは最近のpythonに組み込まれています。または、これを使用できます:http : //code.activestate.com/recipes/576693/)。

新しいpythonのjson実装は組み込みのOrderedDictsを正しく処理すると思いますが、よくわかりません(テストに簡単にアクセスできません)。

古いpythonのsimplejson実装はOrderedDictオブジェクトを適切に処理せず、通常の辞書に変換してから出力しますが、次のようにしてこれを克服できます。

class OrderedJsonEncoder( simplejson.JSONEncoder ):
   def encode(self,o):
      if isinstance(o,OrderedDict.OrderedDict):
         return "{" + ",".join( [ self.encode(k)+":"+self.encode(v) for (k,v) in o.iteritems() ] ) + "}"
      else:
         return simplejson.JSONEncoder.encode(self, o)

これを使用すると、次のようになります。

>>> import OrderedDict
>>> unordered={"id":123,"name":"a_name","timezone":"tz"}
>>> ordered = OrderedDict.OrderedDict( [("id",123), ("name","a_name"), ("timezone","tz")] )
>>> e = OrderedJsonEncoder()
>>> print e.encode( unordered )
{"timezone": "tz", "id": 123, "name": "a_name"}
>>> print e.encode( ordered )
{"id":123,"name":"a_name","timezone":"tz"}

これは、希望どおりです。

別の方法としては、行クラスを直接使用するようにエンコーダーを特化し、中間のdictやUnorderedDictは必要ありません。


5
JSONオブジェクトはまだ順序付けされていないことに注意してください。JSONクライアントはオブジェクト定義を読み取り、キーの順序を完全に無視して、完全にRFCに準拠できます。
Martijn Pieters

4
Martijnは正しいです。これはRFC準拠には影響しませんが、JSONの一貫したフォーマットが必要な場合(たとえば、ファイルがバージョン管理されている場合、または人間の読者が簡単にできるようにする場合)は、確かに依然として価値があります。理解し、エントリの順序をドキュメントと一致させる。)
Michael Anderson

3
その場合は、を呼び出すときにに設定sort_keysするだけです。順序を安定させるには(テスト、安定したキャッシング、またはVCSコミットの場合)、ソートキーで十分です。Truejson.dumps()
Martijn Pieters

7

辞書の順序は、定義された順序とは関係ありません。これは、JSONに変換された辞書だけでなく、すべての辞書に当てはまります。

>>> {"b": 1, "a": 2}
{'a': 2, 'b': 1}

確かに、辞書は到達する前に「逆さま」にされましたjson.dumps

>>> {"id":1,"name":"David","timezone":3}
{'timezone': 3, 'id': 1, 'name': 'David'}

6

ちょっと私はこの答えには遅すぎることを知っていますが、次のようにsort_keysを追加してそれにfalseを割り当てます:

json.dumps({'****': ***},sort_keys=False)

これは私のために働いた


4

json.dump()は辞書の順序を保存します。テキストエディタでファイルを開くと、表示されます。OrderedDictを送信するかどうかに関係なく、注文を保持します。

しかし、json.load()は、OrderedDict()にロードするように指示しない限り、保存されたオブジェクトの順序を失います。

通常の操作では、保存されたディクショナリオブジェクトを通常のdictにロードし、通常のdictは指定されたアイテムの順序を保持しないため、それ以外の場合は順序を失います。


ロード時の順序を維持すると、ダンプ時間の順序付けが処理されるため、これは実際にはより良い修正です。この回答をありがとう。
Arun R

2

JSONでは、JavaScriptと同様に、オブジェクトキーの順序は意味がないため、実際にそれらが表示される順序は関係ありません。同じオブジェクトです。


(標準のPythonについても同様ですdict

12
ただし、JSONは解析されるまで文字列表現であるため、文字列の比較(doctestなど)でも順序が必要な場合があります。だから私はそれが重要ではないとは言いません。
Michael Scott Cuthbert 2014年

1
これはJavascript(ECMAスクリプト)標準に当てはまりますが、すべての実装では(文字列)キーをソース順に保持します。
thebjorn

1
@Paulpro本当に?どれ?Chromeがここで一度標準に準拠しようとしたことを知っていましたが、提出に打ち込まれました(code.google.com/p/v8/issues/detail?id=164)。その後、誰もが同じことをしようとは思わなかった...
thebjorn

2
@paulproあなたはOPの質問に正しく対処しています。ただし、順序を維持するための正当な用途があることを付け加えておきます。たとえば、JSONを読み取り、変換を適用し、結果を書き戻すスクリプトを作成できます。差分ツールで変更が明確に示されるように、順序を維持する必要があります。
Paul Rademacher
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.