2015-08-20 17 views
5

Tôi đang phân tích cú pháp JSON từ api web và Python có vẻ làm xáo trộn các phím khi tôi lặp lại chúng.Các khóa JSON được xáo trộn bằng Python

JSON gốc trên ảnh chụp màn hình (. Nó ngay ban đầu đặt hàng Không, nó không chỉ theo thứ tự abc sắp xếp): Original JSON

Mã của tôi:

data = requests.get('http://www.dota2.com/jsfeed/heropediadata?feeds=abilitydata&l=english').json() 

for key in data['abilitydata']: 
    print key 

Và đầu ra:

tiny_avalanche 
rubick_fade_bolt 
doom_bringer_devour 
undying_flesh_golem 
... 

tôi cũng đã cố gắng làm điều này thông qua urllib & json.loads() - nó cho kết quả tương tự.

Làm cách nào để có thể đạt được thứ tự ban đầu?

+0

Bạn có thể đọc nó bằng cách đối tượng, và khi bạn đọc từng đối tượng thêm một phím theo thứ tự. Tôi chưa bao giờ làm việc với JSON nhưng tôi sẽ tưởng tượng một cái gì đó như lần đầu tiên đọc tệp và sau đó lặp lại từng đối tượng và khi nó được chuyển đổi thành JSON thêm thuộc tính mới - thứ tự ban đầu – PyNEwbie

+1

Đối tượng JSON là [theo định nghĩa] (http://www.json.org), "một tập hợp các cặp tên/giá trị không theo thứ tự". Bạn thực sự không nên sử dụng các đối tượng JSON (hoặc có lẽ bạn thậm chí không nên sử dụng JSON) nếu thứ tự mà trong đó các cặp khóa-giá trị được chỉ định ban đầu là quan trọng. –

Trả lời

5

Bạn có thể sử dụng từ điển được đặt hàng và đối số object_pairs_hook của phương thức tải trong gói json.Dưới đây là một ví dụ mã làm việc:

import json 
import requests 
from collections import OrderedDict 

result = requests.get('http://www.dota2.com/jsfeed/heropediadata?feeds=abilitydata&l=english') 
data = json.loads(result.text, object_pairs_hook = OrderedDict) 

dữ liệu sẽ chứa các phím từ điển của bạn theo thứ tự

+0

Cảm ơn, đã làm việc cho tôi và đây là giải pháp ngắn nhất :) – arts777

1

Vì từ điển Python không có thứ tự.

Khi bạn phân tích cú pháp văn bản JSON, bạn sẽ nhận được một từ điển. Vì loại từ điển không có thứ tự nên các khóa chỉ có thể được lặp lại theo thứ tự không xác định.

+0

Cảm ơn bạn đã giải thích. Có cách nào để lặp lại nó với thứ tự ban đầu không? – arts777

+6

Ngay cả khi sử dụng một loại Python duy trì thứ tự (ví dụ: orderict, mà sẽ phải được sử dụng thông qua-và-through) vẫn không chính xác để dựa vào hành vi này trong JSON; JSON tự thiết lập rõ ràng * no * thứ tự các giá trị khóa/giá trị. – user2864740

+0

@ user2864740 đó chỉ là trình phân tích cú pháp tiện ích, không phải mã sản phẩm liên quan :) – arts777

1

dict loại là kiểu được xây dựng trong Python. Nó không có thứ tự.

Nếu bạn muốn có thể khôi phục thứ tự các khóa trong dict, bạn có thể sử dụng OrderedDict từ lớp collections.

Xem ví dụ này:

>>> import collections 
>>> data = collections.OrderedDict() 
>>> data['pear'] = 1 
>>> data['apple'] = 3 
>>> data['orange'] = 2 
>>> data['lemon'] = 4 
>>> 
>>> 
>>> print data 
OrderedDict([('pear', 1), ('apple', 3), ('orange', 2), ('lemon', 4)]) 
>>> 
>>> 
>>> data2 = dict() 
>>> data2['pear'] = 1 
>>> data2['apple'] = 3 
>>> data2['orange'] = 2 
>>> data2['lemon'] = 4 
>>> 
>>> 
>>> print data2 
{'orange': 2, 'lemon': 4, 'pear': 1, 'apple': 3} 
>>> 

Mọi chi tiết, đi qua này: https://docs.python.org/2/library/collections.html#collections.OrderedDict

3

Như những người khác đã nói, dict là không có thứ tự. collections.OrderedDict là lớp con dict có khóa được sắp xếp. Vấn đề là json.load trả về một trực tiếp dict và chúng tôi không thể ném kết quả theo số OrderedDict vì thứ tự của các khóa đã bị mất thông tin trước thời điểm này.

Chúng ta cần một cách để nói json.load để trả lại một OrderedDict thay vì một dict .Đây có thể được thực hiện bằng cách thực hiện một phong tục json.JSONDecoder mà cung cấp một object_pairs_hook. object_pairs_hook được cung cấp một đối tượng JSON dưới dạng danh sách (key, value) tuples theo thứ tự chúng xuất hiện trong tài liệu JSON. Nó sẽ trả về bản dịch của đối tượng này thành đối tượng Python. Chúng tôi sẽ đưa danh sách các bộ dữ liệu này tới bộ khởi tạo cho collections.OrderedDict và điều đó sẽ thực hiện thủ thuật.

Dưới đây là một số mã:

data = """ 
{ 
    "foo": "bar", 
    "a_list": [1, 2, 3], 
    "another_object": { 
     "c": 3, 
     "a": 1, 
     "b": 2 
     }, 
    "last_key": 42 
} 
""" 

decoder = json.JSONDecoder(object_pairs_hook=collections.OrderedDict) 
result = decoder.decode(data) 
print(result) 

mang đến cho:

OrderedDict([('foo', 'bar'), 
      ('a_list', [1, 2, 3]), 
      ('another_object', OrderedDict([('c', 3), ('a', 1), ('b', 2)])), 
      ('last_key', 42)]) 

Cuối cùng, bạn có thể tự hỏi: "tại sao là việc làm thêm rất nhiều này?". Vâng, JSON không được coi là một cấu trúc dữ liệu với bất kỳ thứ tự cố định nào. Bạn sẽ chống lại hạt bằng cách làm điều này.

+0

Cảm ơn! Lời giải thích tuyệt vời. – arts777

Các vấn đề liên quan