0

I'm trying to get a response from http://steamcommunity.com/profiles/76561198081591043/inventory/json/730/2 in python using requests.

import requests    
url =  "http://steamcommunity.com/profiles/76561198081591043/inventory/json/730/2"   
r = requests.get(url)
print r.text
print r.json()

r.text and r.json() return the objects ordered differently. In 'rgInventory' for instance the first 3 "ids": in .text end in 925, 658, 891 but in .json() end in 891, 619, 741 (just co-incidence that they're descending).

json.loads(r.text) yields the same result

How do i get the json objects to be in the same order as .text shows them?

N Kiolp
  • 11
  • 2
  • 2
    You don't. JSON Objects map to Python Dictionaries, which are inherently unordered. – g.d.d.c May 15 '15 at 22:37
  • it's not so much "unordered" as "arbitrarily ordered": the order of items is determined based on the hashing function, which depends on your particular flavor of Python, and should not be relied upon. is there any reason why it must be ordered exactly as in the text? – oxymor0n May 15 '15 at 22:40
  • I don't understand the unordered part, if I use iteritems() to cycle through the object (r['rgInventory'][i]['id'] and print that, I'll always get them returned in the same order, as shown by the print – N Kiolp May 15 '15 at 22:48
  • As @oxymor0n explained, they _are_ ordered, just that it's in an arbitrary way determined by Python's dictionary internals (which you can't change). A workaround is to map the JSON objects to `OrderedDict`s instead as user2357112's [answer below](http://stackoverflow.com/a/30269908/355230) suggests — although doing so is likely unnecessary depending on what you're trying to accomplish. – martineau May 15 '15 at 23:31

3 Answers3

2

This is probably unnecessary, and if it is necessary, either your code or the Steam API is broken. Judging by your comments, it's probably unnecessary. That said, it's doable.

json.loads takes an optional object_pairs_hook argument. This specifies a function that will be called with a list of key-value pairs to decode object literals. The default is equivalent to specifying object_pairs_hook=dict; to preserve the order the keys appeared in the raw text, you can use object_pairs_hook=collections.OrderedDict:

import collections, json
data = json.loads(response_string, object_pairs_hook=collections.OrderedDict)

r.json() passes keyword arguments along to json.loads, so it should support the same argument:

data = r.json(object_pairs_hook=collections.OrderedDict)
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • It's only necessary because steam doesn't have a proper API for inventories and the text values returned are in order of most recent first, so for checking for inventory updates it's easiest this way, thanks for the reply I'll try it out in the mroning – N Kiolp May 15 '15 at 23:32
0

JSON objects are not sorted per definition of javascript (Does JavaScript Guarantee Object Property Order?). To get the desired result, you would have to sort the resulting dictionary by keys: How can I sort a dictionary by key?

Community
  • 1
  • 1
0

The order of fields in a JSON object is explicitly meaningless and need not be preserved. Many implementations are hashtables, for efficiency.

If JSON order matters, you MUST use an array -- in this case the simplest model might be an array containing two-element arrays, each of which in turn contains a string name and a value.

The other solution would be to use non-JSON string processing code to massage the JSON object fields back into your preferred order. Not recommended!

Sorry, but a difference which the spec doesn't recognize is simply not a difference.

keshlam
  • 7,931
  • 2
  • 19
  • 33