Basj
Basj

Reputation: 46473

Read a JSON and convert the keys to int

It is well known that json converts integer keys of a dict to string:

import json
print json.dumps({1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]})
# {"1": [2.5, 2.5, 2.5], "2": [3, 3, 3, 3]}

What's the cleanest way to restore integer keys when loading it back?

d = json.loads('{"1": [2.5, 2.5, 2.5], "2": [3, 3, 3, 3]}')
print d
# {u'1': [2.5, 2.5, 2.5], u'2': [3, 3, 3, 3]}

I was thinking about:

d = {int(k): d[k] for k in d}

but is there a cleaner way to deal with dictionaries with integer keys with JSON / Python, not requiring keys conversion a posteriori?

Upvotes: 10

Views: 9087

Answers (2)

Isa Rota
Isa Rota

Reputation: 563

I also want to add another solution if you would have a nested dictionary.


I've seen this solution under another question which handles ordinary dictionaries and also nested dictionaries which gives error if you have non-integer keys in the second layers.

>>> import json
>>> json_data = '{"1": "one", "2": {"-3": "minus three", "4": "four"}}'
>>> py_dict = json.loads(json_data, object_hook=lambda d: {int(k) 
                         if k.lstrip('-').isdigit() else k: v for k, v in d.items()})
>>> py_dict
{1: 'one', 2: {-3: 'minus three', 4: 'four'}}

As we can see that object_hook is used to solve the problem, and lstrip('-') is used to handle negative values, too.

Upvotes: 5

Austin
Austin

Reputation: 26039

Use object_hook to define a custom function and perform operations:

import json

def keystoint(x):
    return {int(k): v for k, v in x.items()}

j = json.dumps({1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]})
# {"1": [2.5, 2.5, 2.5], "2": [3, 3, 3, 3]}

print(json.loads(j, object_hook=keystoint))
# {1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]}

From docs:

object_hook is an optional function that will be called with the result of any object literal decoded (a dict). The return value of object_hook will be used instead of the dict.


Or, you could also use object_pairs_hook that lets you iterate through pairs and saves the .items() call (Thanks @chepner):

import json

def keystoint(x):
    return {int(k): v for k, v in x}

j = json.dumps({1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]})
# {"1": [2.5, 2.5, 2.5], "2": [3, 3, 3, 3]}

print(json.loads(j, object_pairs_hook=keystoint))
# {1: [2.5, 2.5, 2.5], 2: [3, 3, 3, 3]}

From docs:

object_pairs_hook is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of object_pairs_hook will be used instead of the dict.

Upvotes: 18

Related Questions