1

このGist の1 行ツリーを使用して、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

明確化

ツリーからキーを返すにはどうすればよいですか? 具体的には、ツリー内のキーの最初の 3 つのレイヤーが取得され、リストに入れられます。例は次のとおりです。

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

{'Animalia': {'Chordata': {'Mammalia': {'Carnivora': {'Canidae': {'Canis': {'coyote': {},
                                                                        'dog': {}}},
                                                  'Felidae': {'Felis': {'cat': {}},
                                                              'Panthera': {'lion': {}}}},
                                    'Cetacea': {'Balaenopteridae': {'Balaenoptera': {'blue whale': {}}}}}}},
 'Plantae': {'Solanales': {'Convolvulaceae': {'Ipomoea': {'sweet potato': {}}},
                       'Solanaceae': {'Solanum': {'potato': {},
                                                  'tomato': {}}}}}}
4

1 に答える 1

2

質問の新しいバージョン(コメント内)では、トップレベルの辞書のすべてのキーと、それぞれに対応する第2レベルの辞書のすべてのキーが必要です。 3番目に。

つまり、ツリーを通るすべてのパスのリストが必要ですが、第 3 レベルで切り捨てられます。それでは、ツリーを深さ優先でウォークスルーし、3 番目のレベルで切り詰めましょう。

まず、単純な深さ優先パス ファインダーを書きましょう。

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,)

以上です:

>>> results = list(prefix_paths(3, taxonomy))
>>> print(results)
[('Animalia', 'Chordata', 'Mammalia'),
 ('Plantae', 'Solanales', 'Solanaceae'),
 ('Plantae', 'Solanales', 'Convolvulaceae')]

実際、コメントで説明しているのは、上位 3 つのレベルのすべてのキーの 1 つのタプルが必要だということです。しかし、上記から簡単にそれを得ることができます。リストを平坦化し、重複を排除するだけです:

>>> 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']

または、代わりに:

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

必要に応じて、ラッパー関数を作成できます。

常に 3 つのキーになることがわかっている場合:

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

それで:

subtree(taxonomy, ('Animalia', 'Chordata', 'Mammalia'))

繰り返しますが、いずれかtaxonomyまたは全体的な結果を渡しdictsて、「クリーン」バージョンを取得できます。

上記のすべてがあなたに与えます:

{'Carnivora': {'Canidae': {'Canis': {'dog': {}}},

'ネコ科': {'フェリス': {'ネコ': {}}, 'パンテーラ': {'ライオン': {}}}}}

(またはその厄介なdefaultdict同等物)。

あなたがそれをさらに良くしたい場合:

pprint.pprint(subtree(dicts(taxonomy), ('Animalia', 'Chordata', 'Mammalia')))

…これにより、次のことが得られます。

{'Carnivora': {'Canidae': {'Canis': {'dog': {}}},
               'Felidae': {'Felis': {'cat': {}},
                           'Panthera': {'lion': {}}}}}}
于 2013-06-26T00:53:13.493 に答える