我有一份清单词典:
a = {
'a': [1, 2, 3],
'b': [1, 2, 4],
'c': [1, 2],
'd': [1, 2, 3, 4, 5],
'e': [3],
'f': [3, 7],
'g': [3, 3],
'h': [3, 3, 3, 3, 3],
'i': [3, 3, 3, 3, 4],
}
我想从这个字典创建层次结构,它将以类似的方式对项目进行分组(确切的结构无关紧要,以及元素之间的关系被保留):
/ \
/ \
e c
/\ /\
f g a b
/\ |
h i d
层次结构如下:数组g
是数组h
和i
的前缀,因此它是它们的祖先。但e
是[{1}}的前缀,因此g
是e
的祖先。
我的想法是如何实现这一结果。
g
我能够实现的。这将给我以下结构:。
s = sorted(a.items(), key=lambda e: len(e[1]))
现在我可以通过迭代元素并检查元素是否是其他元素的前缀来找到第一个父元素。从第一个开始。 ('e', [3])
('c', [1, 2])
('g', [3, 3])
('f', [3, 7])
('a', [1, 2, 3])
('b', [1, 2, 4])
('d', [1, 2, 3, 4, 5])
('h', [3, 3, 3, 3, 3])
是e
,g
和f
的前缀。 h
是[{1}},c
,a
的前缀。b
。所以这两个元素就是父母。
现在我明白我必须使用递归来进入每个父母的内部并执行相同的操作,但我无法找到正确的解决方案。
所以有人知道如何解决这个问题。或者我过度复杂化,有一种更简单的方法来实现解决方案。
P.S。这不是家庭作业或面试问题(也可能是)。这只是我想要解决的问题的抽象。
答案 0 :(得分:1)
其他人已经给出了这个方法,我只是在这里写一些代码:
首先排序:
t = sorted(a.items(), key=lambda x: x[1])
构建结构
ret = {}
def build(ret, upv):
if not t:
return (None, None)
k, v = t.pop(0)
while k and v:
if upv and v[:len(upv)] != upv:
return (k, v)
r = {}
ret[k] = r
k, v = build(r, v)
return None, None
build(ret, None)
print ret
答案 1 :(得分:0)
如果一个对象有一个子列表,一个is_prefix函数,以及你的对象排序列表,我不明白为什么这不起作用
for indx, potential_prefix in enumerate(your_list):
for potential_child in your_list[indx:]:
if is_prefix(potential_prefix, potential_child):
potential_prefix.add_child(potential_child)
# and optionally
potential_child.add_parent(potential_prefix)
答案 2 :(得分:0)
如何使用一组嵌套字典构建树,以便按e
访问tree[3]
节点,h
访问tree[3][3][3][3][3]
节点:< / p>
from collections import nested
def nested():
return defaultdict(nested)
def build_tree(data):
tree = nested()
for name, path in data.items():
d = tree
for p in path:
d = d[p]
d["value"] = name
return tree
示例输出:
>>> a = {
'a': [1, 2, 3],
'b': [1, 2, 4],
'c': [1, 2],
'd': [1, 2, 3, 4, 5],
'e': [3],
'f': [3, 7],
'g': [3, 3],
'h': [3, 3, 3, 3, 3],
'i': [3, 3, 3, 3, 4],
}
>>> import json # for pretty printing, note that in python the keys are ints, not str
>>> print(json.dumps(build_tree(a), indent=4))
{
"1": {
"2": {
"3": {
"4": {
"5": {
"value": "d"
}
},
"value": "a"
},
"4": {
"value": "b"
},
"value": "c"
}
},
"3": {
"7": {
"value": "f"
},
"3": {
"3": {
"3": {
"3": {
"value": "h"
},
"4": {
"value": "i"
}
}
},
"value": "g"
},
"value": "e"
}
}
答案 3 :(得分:0)
按字典顺序对数组进行排序:
(c,[1,2]),
(a,[1,2,3]),
(d,[1,2,3,4,5]),
(b,[1,2,4]),
(e,[3]),
(g,[3,3]),
(h,[3,3,3,3,3]),
(i,[3,3,3,3,4]),
(f,[3,7])
然后解决方案非常明显。
root
Lc
|La
||Ld
|Lb
Le
Lg
|Lh
|Li
Lf
您只需要通过前缀跟踪父级的路径。从上一行开始。你会像堆栈一样形成一些思考。 root
有空集,所以把它推到堆栈上。 c
以(空)前缀为根,因此root
是c
的父级。在堆栈上推c
。 a
在堆栈顶部有c
前缀,因此c
是a
的父级。在堆栈上推送a
。 d
在堆栈顶部的前缀与a
相同,因此a
是d
的父级并推送堆栈。 b
在堆栈顶部没有前缀d
,因此弹出。同样为a
然后弹出。现在c
为前缀,因此b
有父c
。在堆栈上推b
。并以同样的方式继续。
在Erlang中简单地说:
-module(tree_from_prefix).
-export([tree/1]).
is_prefix(_, []) -> true;
is_prefix([H|A], [H|B]) -> is_prefix(A, B);
is_prefix(_, _) -> false.
tree(L) ->
tree(lists:keysort(2, L), [{root, []}]).
tree([], _) -> [];
tree([{X, L} = Record|T] = List, [{Parent, Prefix}|R] = Stack) ->
case is_prefix(L, Prefix) of
true -> [{Parent, X}|tree(T, [Record|Stack])];
false -> tree(List, R)
end.
结果
1> tree_from_prefix:tree([{e,[3]},{c,[1, 2]},{g,[3, 3]},{f,[3, 7]},{a,[1, 2, 3]},{b, [1, 2, 4]},{d,[1, 2, 3, 4, 5]},{h,[3, 3, 3, 3, 3]},{i,[3, 3, 3, 3, 4]}]).
[{root,c},
{c,a},
{a,d},
{c,b},
{root,e},
{e,g},
{g,h},
{g,i},
{e,f}]
在python中它不会那么优雅,但同样的算法也会起作用。