Reputation: 113
Given the JSON below, what would be the best way to create a hierarchical list of "name" for a given "id"? There could be any number of sections in the hierarchy.
For example, providing id "156" would return "Add Storage Devices, Guided Configuration, Configuration"
I've been looking into using iteritems()
, but could do with some help.
{
"result": true,
"sections": [
{
"depth": 0,
"display_order": 1,
"id": 154,
"name": "Configuration",
"parent_id": null,
"suite_id": 5
},
{
"depth": 1,
"display_order": 2,
"id": 155,
"name": "Guided Configuration",
"parent_id": 154,
"suite_id": 5
},
{
"depth": 2,
"display_order": 3,
"id": 156,
"name": "Add Storage Devices",
"parent_id": 155,
"suite_id": 5
},
{
"depth": 0,
"display_order": 4,
"id": 160,
"name": "NEW",
"parent_id": null,
"suite_id": 5
},
{
"depth": 1,
"display_order": 5,
"id": 161,
"name": "NEWS",
"parent_id": 160,
"suite_id": 5
}
]
}
Upvotes: 1
Views: 733
Reputation: 1057
you can also do like this. But for this your input should be like.
Replace null
with None
and true
with True
in your input dictionary.
def filtering(d,id_n):
names = []
while id_n:
id_n,name=[(sec['parent_id'],sec['name']) for sec in d['sections'] if sec['id'] == id_n][0]
names.append(name)
return names
d = {
"result": True, #making 'true' with 'True'
"sections": [
{
"depth": 0,
"display_order": 1,
"id": 154,
"name": "Configuration",
"parent_id": None,
"suite_id": 5
},
{
"depth": 1,
"display_order": 2,
"id": 155,
"name": "Guided Configuration",
"parent_id": 154,
"suite_id": 5
},
{
"depth": 2,
"display_order": 3,
"id": 156,
"name": "Add Storage Devices",
"parent_id": 155,
"suite_id": 5
},
{
"depth": 0,
"display_order": 4,
"id": 160,
"name": "NEW",
"parent_id": None,
"suite_id": 5
},
{
"depth": 1,
"display_order": 5,
"id": 161,
"name": "NEWS",
"parent_id": 160,
"suite_id": 5
}
]
}
testing the code with given inputs:-
id_n = 156
>>> filtering(d,id_n)
['Add Storage Devices', 'Guided Configuration', 'Configuration']
Upvotes: 0
Reputation: 101989
I believe you want something like:
def get_name_for_id(id_num, sections):
cur_depth = -1
texts = []
for elem in sections:
if elem['depth'] < cur_depth:
del texts[:]
elif elem['depth'] == cur_depth:
texts.pop()
texts.append(elem['name'])
cur_depth = elem['depth']
if elem['id'] == id_num:
return ', '.join(reversed(texts))
With your data it returns:
In [11]: get_name_for_id(156, data['sections'])
Out[11]: 'Add Storage Devices, Guided Configuration, Configuration'
Also it takes into account the hierarchy based on depth
, thus if in your data the id
156 refers to depth = 0
the result is:
In [16]: get_name_for_id(156, data['sections'])
Out[16]: 'Add Storage Devices'
If the depth of the id 156 was 1 then the value returned is:
In [22]: get_name_for_id(156, data['sections'])
Out[22]: 'Add Storage Devices, Configuration'
Basically it considers the trees:
depth 156 = 0 depth 156 = 1 depth 156 = 2
154 156 154 154
| | |
| / \ 155
155 155 156 |
156
And it returns the concatenation of the names in the path from the 156 to the root of the tree.
Upvotes: 0
Reputation: 59168
Here's one approach:
def get_path(data, section_id):
path = []
while section_id is not None:
section = next(s for s in data["sections"] if s["id"] == section_id)
path.append(section["name"])
section_id = section["parent_id"]
return ", ".join(path)
... which assumes that data
is the result of json.loads(json_text)
or similar, and section_id
is an int
(which is what you've got for ids in that example JSON).
For your example usage:
>>> get_path(data, 156)
u'Add Storage Devices, Guided Configuration, Configuration'
Upvotes: 2
Reputation: 388023
This is probably what you want:
>>> sections = data['sections']
>>> lookup = {section['id']: section for section in sections}
>>> lookup[None] = {}
>>> for section in sections:
parent = lookup[section['parent_id']]
if 'childs' not in parent:
parent['childs'] = []
parent['childs'].append(section)
>>> def printRecurse (section, indent = 0):
if 'childs' in section:
section['childs'].sort(lambda x: x['display_order'])
for child in section['childs']:
print('{}{}: {}'.format(' ' * indent, child['id'], child['name']))
printRecurse(child, indent + 1)
>>> printRecurse(lookup[None])
154: Configuration
155: Guided Configuration
156: Add Storage Devices
160: NEW
161: NEWS
Upvotes: 0
Reputation: 229
Probably the simplest way is to create a dictionary mapping the IDs to names. For example:
name_by_id = {}
data = json.loads(the_json_string)
for section in data['sections']:
name_by_id[section['id']] = section['name']
or using dict comprehensions:
name_by_id = {section['id']: section['name'] for section in data['sections']}
then you can get specific element:
>>> name_by_id[156]
... 'Add Storage Devices'
or get all IDs:
>>> name_by_id.keys()
... [160, 161, 154, 155, 156]
Upvotes: 0