user956424
user956424

Reputation: 1609

Create hierarchical json dump from list of dictionary in python

The table:

categories = Table("categories", metadata,
                   Column("id", Integer, primary_key=True),
                   Column("name", String),
                   Column("parent_id", Integer, ForeignKey("categories.id"),
                          CheckConstraint('id!=parent_id'), nullable=True),

)

A category can have many children, but only 1 parent. I have got the list of dictionary values as follows using CTE: eg. For id :14, parent is 13 and traversed from parent 8->10->12->13->14 where parent 8 has no parent id.

[
    {
      "id": 14, 
      "name": "cat14", 
      "parent_id": 13, 
      "path_info": [
        8, 
        10, 
        12, 
        13, 
        14
      ]
    }, 
    {
      "id": 15, 
      "name": "cat15", 
      "parent_id": 13, 
      "path_info": [
        8, 
        10, 
        12, 
        13, 
        15
      ]
    }
  ]

I would like to get the attributes of the parent also embedded as subcategories in the list as:

{
  "id": 14, 
  "name": "cat14", 
  "parent_id": 13, 
  "subcats": [
       {
         "id: 8", 
         "name": "cat8", 
         "parent_id":null
       }, 
       {
         "id: 10", 
         "name": "cat10", 
         "parent_id":8
       },  
       {
         "id: 12", 
         "name": "cat12", 
         "parent_id":10
       },   
      and similarly for ids 13 and 14..... 
     ]
}, 
{
  "id": 15, 
  "name": "cat15", 
  "parent_id": 13, 
  "subcats": [
       {
         "id: 8", 
         "name": "cat8", 
         "parent_id":null
       }, 
       {
         "id: 10", 
         "name": "cat10", 
         "parent_id":8
       },  
       {
         "id: 12", 
         "name": "cat12", 
         "parent_id":10
       },   
       and similarly for ids 13, 14, 15..... 
     ]
}

] Notice that 'path_info' has been deleted from the dictionary and each id has been displayed with its details. I want json dumps with the above indented format. How to go about? Using flask 0.10, python 2.7

Upvotes: 9

Views: 8451

Answers (3)

hilberts_drinking_problem
hilberts_drinking_problem

Reputation: 11602

There is a tolerable way to do this with a few list/dict comprehensions.

lst = [{"id": 14, "name": "cat14", "parent_id": 13, "path_info": [8, 10, 12, 13, 14]}, {"id": 15, "name": "cat15", "parent_id": 13, "path_info": [8, 10, 12, 13, 15]}]

master_dct = { d['id'] : d for d in lst}
for d in lst:
    d['subcats'] = [{field : master_dct[i][field] for field in ['id', 'name', 'parent_id']} \
        for i in d['path_info'] if i in master_dct]

import json
with open('out.json', 'w') as f:
    json.dump(lst, f)

Upvotes: 3

Aman Chhabra
Aman Chhabra

Reputation: 627

The pythonic code for this: Simple and straightforward

import json
categories = [] #input
def transform(category, child_node_id):
    category['subcats'].append({
       'id': child_node_id,
       'name': 'cat%s' % child_node_id,
       'parent_id': category['id']
    })


for category in categories:
    category['subcats'] = []
    [transform(category, child_node_id) for child_node_id in category['path_info']]
    category.pop('path_info', None)

print(json.dumps(categories, indent=4))

Upvotes: 1

Eugene Lisitsky
Eugene Lisitsky

Reputation: 12875

You can perform it in python code:

Given we have a json object. I've slightly modified it - added absent nodes and wrap into an object as it is required by the specification:

    {
      "array": [
          {
            "id": 14, 
            "name": "cat14", 
            "parent_id": 13, 
            "path_info": [
              8, 
              10, 
              12, 
              13, 
              14
            ]
          }, 
          {
            "id": 15, 
            "name": "cat15", 
            "parent_id": 13, 
            "path_info": [
              8, 
              10, 
              12, 
              13, 
              15
            ]
          },
          {
            "id": 13, 
            "name": "cat13", 
            "parent_id": 12, 
            "path_info": [
              8, 
              10, 
              12, 
              13
            ]
          },
         {
            "id": 12, 
            "name": "cat12", 
            "parent_id": 10, 
            "path_info": [
              8, 
              10, 
              12
            ]
          }, 
          {
            "id": 10, 
            "name": "cat10", 
            "parent_id": 8, 
            "path_info": [
              8, 
              10
            ]
          },
          {
            "id": 8, 
            "name": "cat8", 
            "parent_id": null, 
            "path_info": [
              8
            ]
          }
        ]
    }

Then you may use following code:

    # load data above from file
    j=json.load(open('json_file_above.json'))   # 

    #  the array with real data we need
    a=j['array']  

    # auxiliary dict which have node identificators as keys and nodes as values
    d={x['id']:x for x in a}  

    # here the magic begins :)
    for x in a:
       # add new key with list to each element
       x['subcats'] = [ 
                       # compose dict element for subcats
                       dict(id=i, name=d[i]['name'], parent_id=d[i]['parent_id'])
                       for 
                       i 
                       in [
                           # we take path_info id list and
                           # cut off the first element - itself
                           y for y in x['path_info'][1:]
                          ]  
                      ]
       del x['path_info']

To be sure you are getting the thing you need:

    >>> print(json.dumps(a, indent=True))
    [
     {
      "name": "cat14",
      "subcats": [
       {
        "name": "cat10",
        "id": 10,
        "parent_id": 8
       },
       {
        "name": "cat12",
        "id": 12,
        "parent_id": 10
       },
       {
        "name": "cat13",
        "id": 13,
        "parent_id": 12
       },
       {
        "name": "cat14",
        "id": 14,
        "parent_id": 13
       }
      ],
      "id": 14,
      "parent_id": 13
     },
     {
      "name": "cat15",
      "subcats": [
       {
        "name": "cat10",
        "id": 10,
        "parent_id": 8
       },
       {
        "name": "cat12",
        "id": 12,
        "parent_id": 10
       },
       {
        "name": "cat13",
        "id": 13,
        "parent_id": 12
       },
       {
        "name": "cat15",
        "id": 15,
        "parent_id": 13
       }
      ],
      "id": 15,
      "parent_id": 13
     },
     {
      "name": "cat13",
      "subcats": [
       {
        "name": "cat10",
        "id": 10,
        "parent_id": 8
       },
       {
        "name": "cat12",
        "id": 12,
        "parent_id": 10
       },
       {
        "name": "cat13",
        "id": 13,
        "parent_id": 12
       }
      ],
      "id": 13,
      "parent_id": 12
     },
     {
      "name": "cat12",
      "subcats": [
       {
        "name": "cat10",
        "id": 10,
        "parent_id": 8
       },
       {
        "name": "cat12",
        "id": 12,
        "parent_id": 10
       }
      ],
      "id": 12,
      "parent_id": 10
     },
     {
      "name": "cat10",
      "subcats": [
       {
        "name": "cat10",
        "id": 10,
        "parent_id": 8
       }
      ],
      "id": 10,
      "parent_id": 8
     },
     {
      "name": "cat8",
      "subcats": [],
      "id": 8,
      "parent_id": null
     }
    ]
    >>>

Upvotes: 1

Related Questions