有一个像这样的元组:
t = (
(1, -1, 'python'),
(2, -1, 'ruby'),
(3, -1, 'php'),
(4, -1, 'lisp'),
(5, 1, 'flask'),
(6, 1, 'django'),
(7, 1, 'webpy'),
(8, 2, 'rails'),
(9, 3, 'zend'),
(10, 6, 'dblog')
)
我想将其更改为列表,每个列表项都是字典。这本词典有一个关键的儿子是另一本字典。如何更改元组t,我希望成为这样的列表字典树:
l = [
{
'id': 1,
'fid': -1,
'title': 'python',
'son': [
{
'id': 5,
'fid': 1,
'title': 'flask',
},
{
'id': 6,
'fid': 1,
'title': 'django',
'son': [
{
'id': 10,
'fid': 6,
'title': 'dblog',
},
]
},
{
'id': 7,
'fid': 1,
'title': 'webpy',
},
]
},
{
'id': 2,
'fid': -1,
'title': 'ruby',
'son': [
{
'id': 8,
'fid': 2,
'title': 'rails',
},
]
},
{
'id': 3,
'fid': -1,
'title': 'php',
'son': [
{
'id': 9,
'fid': 3,
'title': 'zend',
},
]
},
{
'id': 4,
'fid': -1,
'title': 'lisp',
}
非常感谢
答案 0 :(得分:1)
l = []
entries = {}
for id, fid, title in t:
entries[id] = entry = {'id': id, 'fid': fid, 'title': title}
if fid == -1:
l.append(entry)
else:
parent = entries[fid]
parent.setdefault('son', []).append(entry)
此处entries
会跟踪到目前为止已创建的所有条目,以便您可以直接向其添加“子”,而无需搜索树。
这假定您的列表t
已按id
正确排序,并且儿子只是较低ID的子项。
演示:
>>> from pprint import pprint
>>> t = (
... (1, -1, 'python'),
... (2, -1, 'ruby'),
... (3, -1, 'php'),
... (4, -1, 'lisp'),
... (5, 1, 'flask'),
... (6, 1, 'django'),
... (7, 1, 'webpy'),
... (8, 2, 'rails'),
... (9, 3, 'zend'),
... (10, 6, 'dblog')
... )
>>> l = []
>>> entries = {}
>>> for id, fid, title in t:
... entries[id] = entry = {'id': id, 'fid': fid, 'title': title}
... if fid == -1:
... l.append(entry)
... else:
... parent = entries[fid]
... parent.setdefault('son', []).append(entry)
...
>>> pprint(l)
[{'fid': -1,
'id': 1,
'son': [{'fid': 1, 'id': 5, 'title': 'flask'},
{'fid': 1,
'id': 6,
'son': [{'fid': 6, 'id': 10, 'title': 'dblog'}],
'title': 'django'},
{'fid': 1, 'id': 7, 'title': 'webpy'}],
'title': 'python'},
{'fid': -1,
'id': 2,
'son': [{'fid': 2, 'id': 8, 'title': 'rails'}],
'title': 'ruby'},
{'fid': -1,
'id': 3,
'son': [{'fid': 3, 'id': 9, 'title': 'zend'}],
'title': 'php'},
{'fid': -1, 'id': 4, 'title': 'lisp'}]
如果“fid-after-after-id”假设不成立,则需要添加一个子ID队列,以便进行处理:
l = []
entries = {}
queue = {}
for id, fid, title in t:
entries[id] = entry = {'id': id, 'fid': fid, 'title': title}
if id in queue:
entry['sons'] = queue[id]
del queue[id]
if fid == -1:
l.append(entry)
elif fid in entries:
parent = entries[fid]
parent.setdefault('son', []).append(entry)
else:
queue.setdefault(fid, []).append(entry)
if queue:
raise ValueError('No entries found for fid(s) {}'.format(queue.keys()))
现在t
中的条目顺序可以完全随机:
>>> import random
>>> t = list(t)
>>> random.shuffle(t)
>>> l = []
>>> entries = {}
>>> queue = {}
>>> for id, fid, title in t:
... entries[id] = entry = {'id': id, 'fid': fid, 'title': title}
... if id in queue:
... entry['sons'] = queue[id]
... del queue[id]
... if fid == -1:
... l.append(entry)
... elif fid in entries:
... parent = entries[fid]
... parent.setdefault('son', []).append(entry)
... else:
... queue.setdefault(fid, []).append(entry)
...
>>> if queue:
... raise ValueError('No entries found for fid(s) {}'.format(queue.keys()))
...
>>> pprint(l)
[{'fid': -1,
'id': 1,
'son': [{'fid': 1, 'id': 7, 'title': 'webpy'},
{'fid': 1, 'id': 5, 'title': 'flask'},
{'fid': 1,
'id': 6,
'sons': [{'fid': 6, 'id': 10, 'title': 'dblog'}],
'title': 'django'}],
'title': 'python'},
{'fid': -1,
'id': 2,
'son': [{'fid': 2, 'id': 8, 'title': 'rails'}],
'title': 'ruby'},
{'fid': -1,
'id': 3,
'son': [{'fid': 3, 'id': 9, 'title': 'zend'}],
'title': 'php'},
{'fid': -1, 'id': 4, 'title': 'lisp'}]
fid
可以是任意id
,只要该ID在序列t
中名为某处,或者对于根条目名称为-1
答案 1 :(得分:0)
创建一个单独的字典,将ID映射到本地id-fid-title-son字典。在单独的字典中找到fid后,将本地字典拼接在一起。如果本地字典的fid为-1,则将其添加到列表中。这是有效的,因为无论包含什么内容,本地字典都是同一个对象。
答案 2 :(得分:0)
如果初始列表已正确订购,请查看Martijn Pieters解决方案。但是,如果您无法保证订单,那么其中一个解决方案是在初始列表上循环两次:
children = {}
objs = []
l = []
for id, parent, title in t:
obj = {
"id": id,
"fid": parent,
"title": title
}
objs.append(obj)
if parent == -1: # keep only roots
l.append(obj)
if parent not in children: # append to children
children[parent] = []
children[parent].append(obj)
for obj in objs:
if obj["id"] in children:
obj["son"] = children[obj["id"]]