问题
How to get from this dict:
cats = [
{'parent_id': False, 'id': 1, 'title': u'All'},
{'parent_id': False, 'id': 2, 'title': u'Toys'},
{'parent_id': 2, 'id': 3, 'title': u'Toypads'},
{'parent_id': 3, 'id': 4, 'title': u'Green'},
]
Something like this?
cats = [
{'parent_id': False, 'id': 1, 'title': u'All'},
{'parent_id': False,
'children': [{'parent_id': 2,
'children': [{'parent_id': 3, 'id': 4,
'title': u'Green'}],
'id': 3, 'title': u'Toypads'},
[{'parent_id': 3, 'id': 4, 'title': u'Green'}]],
'id': 2, 'title': u'Toys'}
]
I need it to build a menu\sub-menu in Jinja2. I wrote a very bad code. It would be a more elegant solution.
q = dict(zip([i['id'] for i in cats], cats))
from collections import defaultdict
parent_map = defaultdict(list)
for item in q.itervalues():
parent_map[item['parent_id']].append(item['id'])
def tree_level(parent):
for item in parent_map[parent]:
yield q[item]
sub_items = list(tree_level(item))
if sub_items:
for ca in cats:
if ca['id'] == item:
cats[cats.index(ca)]['children'] = sub_items
for s_i in sub_items:
try:
for ca_del_child in cats:
if ca_del_child['id'] == s_i['id']:
del cats[cats.index(ca_del_child)]
except:
pass
yield sub_items
for i in list(tree_level(False)):
pass
回答1:
Here is a fairly concise solution:
cats = [{'parent_id': False, 'id': 1, 'title': u'All'},
{'parent_id': False, 'id': 2, 'title': u'Toys'},
{'parent_id': 2, 'id': 3, 'title': u'Toypads'},
{'parent_id': 3, 'id': 4, 'title': u'Green'},]
cats_dict = dict((cat['id'], cat) for cat in cats)
for cat in cats:
if cat['parent_id'] != False:
parent = cats_dict[cat['parent_id']]
parent.setdefault('children', []).append(cat)
cats = [cat for cat in cats if cat['parent_id'] == False]
Note that the comparisons to False are generally not necessary, but they should be used here in case you had a cat with 0 as its id or parent_id. In this case I would use None
instead of False
for a cat with no parent.
回答2:
It can be done as follows:
# Step 1: index all categories by id and add an element 'children'
nodes = {}
for cat in cats:
nodes[cat['id']] = cat
cat['children'] = []
# Step 2: For each category, add it to the parent's children
for index, cat in nodes.items():
if cat['parent_id']:
nodes[cat['parent_id']]['children'].append(cat)
# Step 3: Keep only those that do not have a parent
cats = [c for c in nodes.values() if not c['parent_id']]
Note that each node will have an attribute called 'children'
, which may be an empty list or a list with one or more nodes. If you don't want empty children
lists, you can simply remove them between step 2 and step from each category in nodes
.
Also note that the above assumes a node with a given parent_id
actually exists. Lastly, note that if not c['parent_id']
will also be true when a node with id zero exists so you'll need to keep than in mind if that can occur.
来源:https://stackoverflow.com/questions/10047643/how-to-create-dict-with-childrens-from-dict-with-parent-id