Python 引用单行树中的单个DICT

Python 引用单行树中的单个DICT,python,list,dictionary,tree,key,Python,List,Dictionary,Tree,Key,我正在使用这一行树轻松地从excel中获取信息。以下是站点中的树示例: def tree(): return defaultdict(tree) taxonomy = tree() taxonomy['Animalia']['Chordata']['Mammalia']['Carnivora']['Felidae']['Felis']['cat'] taxonomy['Animalia']['Chordata']['Mammalia']['Carnivora']['Felidae']['Pant

我正在使用这一行树轻松地从excel中获取信息。以下是站点中的树示例:

def tree(): return defaultdict(tree)
taxonomy = tree()
taxonomy['Animalia']['Chordata']['Mammalia']['Carnivora']['Felidae']['Felis']['cat']
taxonomy['Animalia']['Chordata']['Mammalia']['Carnivora']['Felidae']['Panthera']['lion']
taxonomy['Animalia']['Chordata']['Mammalia']['Carnivora']['Canidae']['Canis']['dog']
然后将其转换为dicts进行漂亮的打印:

def dicts(t):
    try:
        return dict((k, dicts(t[k])) for k in t)
    except TypeError:
        return t
澄清

如何从树中返回密钥?具体来说,树中的前三层键将被获取并放入一个列表中。例如:

('Animalia', 'Chordata', 'Mammalia','Plantae', 'Solanales', 'Convolvulaceae') 


对于问题的新版本(在您的评论中),您需要的是顶级dict的所有键,对于每一个,对应的第二级dict的所有键,对于第三级dict同样

换句话说,您需要一个通过树的所有路径的列表,但在第三级被截断。那么,让我们先做一个深度优先遍历树,然后在第三层截断

首先,让我们编写一个简单的深度优先路径查找程序:

def paths(tree, path=()):
    for key, subtree in tree.items():
        if subtree:
            yield from paths(subtree, path + (key,))
        else:
            yield path + (key,)
现在,让我们在深度3处截断它:

def prefix_paths(prefix_length, tree, path=()):
    for key, subtree in tree.items():
        if subtree and len(path) + 1 < prefix_length:
            yield from prefix_paths(prefix_length, subtree, path + (key,))
        else:
            yield path + (key,)

实际上,您在注释中描述的是,您需要一个包含前三个级别中所有键的元组。但是你可以很容易地从上面得到。只需展平列表并消除重复项:

>>> flatten = itertools.chain.from_iterable
>>> keys = flatten(prefix_paths(3, taxonomy))
>>> unique_keys = tuple(set(keys))
>>> print(unique_keys)
('Chordata', 'Convolvulaceae', 'Plantae', 'Solanales', 'Animalia', 'Mammalia', 'Solanaceae')
(顺便说一句,顺序是完全不确定的,因为字典就是这样工作的;我碰巧得到了与你评论中相同的顺序,这只是一个意外,你不应该依赖它……)


同时,这里是我对你问题的原始版本的回答(这仍然是问题中的问题…)

就是这个,

taxonomy['Animalia']['Chordata']['Mammalia']
或者,如果您想要“干净”版本:

或者,或者:

dicts(taxonomy['Animalia']['Chordata']['Mammalia'])

如果愿意,可以编写包装器函数

如果你知道它总是有三个键:

def subtree(tree, three_keys):
    return tree[three_keys[0]][three_keys[1]][three_keys[2]]
如果希望它使用任意数量的键:

def subtree(tree, keys):
    while keys:
        tree, keys = tree[keys[0]], keys[1:]
    return tree
然后:

同样,您可以将
taxonomy
或整体结果传递给
dicts
,以获得“干净”版本

以上所有内容都为您提供了:

{'Carnivora': {'Canidae': {'Canis': {'dog': {}}},
猫科动物:{'Felis':{'cat':{},'Panthera':{'lion':{}

(或其凌乱的
defaultdict
等价物)

如果您想让它变得更好:

pprint.pprint(subtree(dicts(taxonomy), ('Animalia', 'Chordata', 'Mammalia')))
…这给了你:

{'Carnivora': {'Canidae': {'Canis': {'dog': {}}},
               'Felidae': {'Felis': {'cat': {}},
                           'Panthera': {'lion': {}}}}}}

对不起,我不清楚。我的意思是我希望所有可能的键都是列表格式。所以最后的列表是:('Plantae','Solanales','convalvaceae','Animalia','Chordata','malemalia')实际上,我想我可能可以将我拥有的树转换成子树,并使用类似于:def dicts(t):return{k:dicts(t[k])的结构来表示t}中的k除了使用def将前三层键返回到列表中之外……我只是随口说说而已。非常感谢!我在问你第二个答案!工作很棒。为了澄清,你说的“第二个答案”是指前3个级别中唯一键的扁平列表:
(“脊索动物”、“旋花科”、“植物”、“茄属”、“动物”、“哺乳动物”、“茄科”)
,对吧?不管怎样,只要你有问题,都可以作为将来的参考“对于一个列表或dict,我会迭代项目和_____;,但是对于一个树我该怎么做呢?”,答案通常与“深度优先遍历节点和_____;密切相关。因此,您可能需要使用几种不同的方法编写深度优先遍历(迭代与递归、生成器与列表返回函数等)巩固你头脑中的想法。文章的编辑版本仍然完全不清楚。原始版本似乎要求单独的子部分。从你的评论来看,这不是你想要的,但是你编辑的问题明确地说这正是你想要的。我试着编辑我的答案来处理所有的问题你似乎已经问过了,但在你弄清楚你问的是哪一个之前,没有人可能会重新打开你的问题。@abarnert我又编辑了一遍。希望现在能更清楚。
subtree(taxonomy, ('Animalia', 'Chordata', 'Mammalia'))
{'Carnivora': {'Canidae': {'Canis': {'dog': {}}},
pprint.pprint(subtree(dicts(taxonomy), ('Animalia', 'Chordata', 'Mammalia')))
{'Carnivora': {'Canidae': {'Canis': {'dog': {}}},
               'Felidae': {'Felis': {'cat': {}},
                           'Panthera': {'lion': {}}}}}}