user712850
user712850

Reputation:

How to convert Python dict to JSON as a list, if possible

I'm trying to serialize my Python objects into JSON using json.dumps. If you serialize a dict using json.dumps it will obviously be serialized as a JSON dictionary {..}; if you serialize a list or a tuple, it will be a JSON array.

I want to know if there's any way to easily serialize a Python dict as a JSON list, if possible. By if possible, I mean if the keys start at 0 and are sequenced, for example:

{0:'data',1:'data',2:'data}

The above would be serialized into JSON as: '{"0": "data", "1": "data", "2": "data"}', but I would like it to be serialized as ['data','data','data'] since the keys start at 0 and are sequenced.

My reasoning for this is because I have lots of JSON data that is serialized from PHP, where in PHP arrays have keys and if the keys are sequenced as described above, PHP's json.encode uses arrays, if they are keyed in any other manner, they are serialized as JSON dictionaries. I want my JSON serializations to match for both my PHP and Python code. Unfortunately, changing the PHP code isn't an option in my case.

Any suggestions? The only solution I have found is to write my own function to go through and verify each python dictionary and see if it can first be converted to a list before json.dumps.

EDIT: This object that I'm serializing could be a list or a dict, as well, it could have additional dicts inside of it, and lists, and so on (nesting). I'm wondering if there's any 'simple' way to do this, otherwise I believe I can write a recursive solution myself. But it's always better to use existing code to avoid more bugs.

Upvotes: 5

Views: 10279

Answers (3)

root
root

Reputation: 80436

I don't know of a solution without recursion... Although you can call your converter from inside the encode method of your custom Encoder, it would just add unnecessary complexity.

In [1]: import json

In [2]: d = {"0": "data0", "1": "data1", "2": {"0": "data0", "1": "data1", "2": "data2"}}

In [3]: def convert(obj):
   ...:     if isinstance(obj, (list, tuple)):
   ...:         return [convert(i) for i in obj]
   ...:     elif isinstance(obj, dict):
   ...:         _, values = zip(*sorted(obj.items()))  
   ...:         return convert(values)
   ...:     return obj

In [4]: json.dumps(convert(d))
Out[4]: '["data0", "data1", ["data0", "data1", "data2"]]'

Upvotes: 2

Trey Hunner
Trey Hunner

Reputation: 11814

Normally you could subclass json.JSONEncoder to create your own custom JSON serializer, but that won't allow you to override built-in object types.

If you create your own custom dictlist object (or whatever you want to call it) that doesn't extend dict or list you should be able to override the JSONEncoder.default method to create your own custom JSON serializer.

Regardless of whether you create a custom JSON serializer or recursively replace your special dict instances with lists you will need a function that accepts a dict and returns either a list or a dict as appropriate.

Here's one implementation:

def convert_to_list(obj):
    obj_list = []
    for i in range(len(obj)):
        if i not in obj:
            return obj  # Return original dict if not an ordered list
        obj_list.append(obj[i])
    return obj_list

Upvotes: 0

Blender
Blender

Reputation: 298532

You could convert the dictionary into a list of tuples and then sort it, as dictionary items won't necessarily come out in the order than you want them to:

items = sorted(d.items(), key=lambda item: item[0])
values = [item[1] for item in items]
json_dict = json.dumps(values)

Upvotes: 2

Related Questions