HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Simplify the restructuring of json data

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
therestructuringsimplifyjsondata

Problem

I am trying to ad nested to some flat data, which is nested.

Basically this code works the following way:

-
"taglevel":1 tags should be key of the array

-
"taglevel":2 or higher tags should be nested within an array and not be duplicated in its' array

-
If no "taglevel":1 exists add, it to a generic "NoLevel_1" array

The code is still clunky and I feel there is a much cleaner way to achieve this.

import json
generic = []
result = []

for i in json_data:
    if any(d['taglevel'] == 1 for d in i['tag']):
        tag_data = {}
        tag_child = []
        for tag in i['tag']:
            if tag['taglevel'] == 1:
                tag_data['name'] = tag['name']
                tag_data['taglevel'] = 1
            else:
                tag_child.append(tag)
        filtered = {tuple((k, d[k]) for k in sorted(d) if k in ['name']): d for d in tag_child}
        tag_data['tag_child'] = list(filtered.values())
        if any(d['name'] == tag_data['name']  for d in result):
            for t in result:
                if t['name'] == tag_data['name']:
                    t['tag_child'] = t['tag_child'] + tag_child
                filtered = {tuple((k, d[k]) for k in sorted(d) if k in ['name']): d for d in t['tag_child']}
            t['tag_child'] = list(filtered.values())
        else:
            result.append(tag_data)
    else:
        for tag in i['tag']:
            generic.append(tag)
tag_data = {}
tag_data['name'] = 'NoLevel1'
tag_data['taglevel'] = 1
tag_data['tag_child'] = generic
result.append(tag_data)
print json.dumps(result, indent=4, sort_keys=True)


The data:

```
json_data = [{
"title": "Random",
"tag": [
{
"name": "Fruit",
"taglevel": 1
},
{
"name": "Apple",
"taglevel": 2
}
]
},
{
"title": "Other",
"tag": [
{
"name": "Fruit",
"taglevel": 1

Solution

Well you may or may not considered this a simplification but this is how I would approach it.

You could use a set to handle the duplication part.

You can't store a dict in a set though so we need to create a tuple from the values. (It looks like you're doing something similar with filtered)

We then reformat result to get the desired final structure.

from collections import defaultdict

result = defaultdict(set)

for item in json_data:
    parent   = {'name': 'NoLevel_1'}
    children = []
    for tag in item['tag']:
        if tag['taglevel'] == 1:
            parent = tag
        else:
            children.append((tag['taglevel'], tag['name']))
    result[parent['name']].update(children)

result = [ 
    {
        'name': parent, 
        'tag_child': [
            {'name': name, 'taglevel': taglevel} for taglevel, name in tags
        ],
        'taglevel': 1, 
    } for parent, tags in result.items()
]


You could use next() and a list comprehension for the parent and child creation however it iterates the tags twice and may not be as "readable"

parent   = next((tag for tag in item['tag'] if tag['taglevel'] == 1), {'name': 'NoLevel_1'})
children = [(tag['taglevel'], tag['name']) for tag in item['tag'] if tag['taglevel'] != 1]

Code Snippets

from collections import defaultdict

result = defaultdict(set)

for item in json_data:
    parent   = {'name': 'NoLevel_1'}
    children = []
    for tag in item['tag']:
        if tag['taglevel'] == 1:
            parent = tag
        else:
            children.append((tag['taglevel'], tag['name']))
    result[parent['name']].update(children)

result = [ 
    {
        'name': parent, 
        'tag_child': [
            {'name': name, 'taglevel': taglevel} for taglevel, name in tags
        ],
        'taglevel': 1, 
    } for parent, tags in result.items()
]
parent   = next((tag for tag in item['tag'] if tag['taglevel'] == 1), {'name': 'NoLevel_1'})
children = [(tag['taglevel'], tag['name']) for tag in item['tag'] if tag['taglevel'] != 1]

Context

StackExchange Code Review Q#161090, answer score: 4

Revisions (0)

No revisions yet.