0

I have the following dictionary, I want to swap 'path' and 'outputs', so that path appears first

 {'outputs': {'path': 'abc.jpg',
    'size': {'width': 1920, 'height': 1080, 'depth': 3},
    'object': [{'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 1532, 'ymin': 631, 'xmax': 1657, 'ymax': 687}},
     {'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 795, 'ymin': 685, 'xmax': 880, 'ymax': 723}},
     {'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 1473, 'ymin': 660, 'xmax': 1529, 'ymax': 690}}]}}

like this

{'path': 'abc.jpg','outputs': {
    'size': {'width': 1920, 'height': 1080, 'depth': 3},
    'object': [{'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 1532, 'ymin': 631, 'xmax': 1657, 'ymax': 687}},
     {'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 795, 'ymin': 685, 'xmax': 880, 'ymax': 723}},
     {'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 1473, 'ymin': 660, 'xmax': 1529, 'ymax': 690}}]}}

This dictionary is obtained by loading a json string. Is there some way of swapping the first two keys of this dictionary?

choroba
  • 231,213
  • 25
  • 204
  • 289
Vendetta
  • 294
  • 4
  • 11
  • 1
    relevant: https://stackoverflow.com/questions/5629023/the-order-of-keys-in-dictionaries – user120242 Jul 15 '20 at 16:38
  • 1
    Does this answer your question? [The order of keys in dictionaries](https://stackoverflow.com/questions/5629023/the-order-of-keys-in-dictionaries) – Marat Jul 15 '20 at 16:39
  • Oh wait... they're at different nesting levels. That's a different problem – user120242 Jul 15 '20 at 16:39
  • If it is important to you in which order the keys are in a dictionary, you are doingsomething wrong. It is a mapping. It lets you get a value for a key. Use it that way. – zvone Jul 15 '20 at 16:48

2 Answers2

2

It's generally a sign that you are doing something you shouldn't, or your data should be organized differently, if you are depending on key order. You may want to clarify your use case to see if there is a better way to achieve what you are trying to do, or a better practice. That said:

Reference: The order of keys in dictionaries
For Python 3.7.0+, insertion order is preserved and in the specs. For Python 3.6+, insertion order is preserved, but only as an implementation detail.
For < 3.6 you will want to use collection.OrderedDict

Re-insert attributes to get the order right for 3.6+:

data={'outputs': {'path': 'abc.jpg',
    'size': {'width': 1920, 'height': 1080, 'depth': 3},
    'object': [{'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 1532, 'ymin': 631, 'xmax': 1657, 'ymax': 687}},
     {'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 795, 'ymin': 685, 'xmax': 880, 'ymax': 723}},
     {'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 1473, 'ymin': 660, 'xmax': 1529, 'ymax': 690}}]}}

data['path'] = data['outputs']['path']
del data['outputs']['path']
data['outputs'] = data.pop('outputs')

collections.OrderedDict for < 3.6. Only difference is that the dict is wrapped in OrderedDict before re-inserting:

data={'outputs': {'path': 'abc.jpg',
    'size': {'width': 1920, 'height': 1080, 'depth': 3},
    'object': [{'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 1532, 'ymin': 631, 'xmax': 1657, 'ymax': 687}},
     {'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 795, 'ymin': 685, 'xmax': 880, 'ymax': 723}},
     {'name': 'vehicle',
    'pose': 'Unspecified',
    'truncated': 0,
    'difficult': 0,
    'bndbox': {'xmin': 1473, 'ymin': 660, 'xmax': 1529, 'ymax': 690}}]}}

from collections import OrderedDict
data = OrderedDict(data)

data['path'] = data['outputs']['path']
del data['outputs']['path']
data['outputs'] = data.pop('outputs')

This is basically just like @choroba's answer, just with detailed explanation and re-insertion to re-arrange key order.

user120242
  • 14,918
  • 3
  • 38
  • 52
  • Thanks a lot for detailed answer. choroba answered first so I had to accept his answer. Your observations are correct about this dictionary. I am swapping this because of a third party tool requiring json to be formatted exactly that way. Otherwise, it does not work and I had to rely on that. Thanks again. – Vendetta Jul 15 '20 at 17:29
1

Use pop to remove the path from withing outputs and create a new toplevel key path to store the removed value.

dict = json.loads(...)
dict["path"] = dict["outputs"].pop("path")

Note that it would place path to the same level as output, but it doesn't have to appear first, as keys of a dictionary are unordered.

choroba
  • 231,213
  • 25
  • 204
  • 289