0

の拡張:辞書のリストの辞書の再帰など (python)

私は4レベルのネストされた辞書構造で作業しています。ネストされた辞書全体を繰り返し処理し、個々の辞書に識別番号を付けようとしています(アイテムのツリーを構築し、どのアイテムノードかを知るための前兆として)親であり、ノードが持つ子など)

私はこの機能を持っています:

def r(y):
    cnt = 1
    def recurse(y, count):
        for i in y.iteritems():
            count+=1
            i['id'] = count
            for k,v in y.iteritems():
                if isinstance(v, list):
                    [recurse(i, count) for i in v]
                else:
                    pass
    recurse(y, cnt)
    return y

辞書のリストのネストされた辞書に入れました。

つまり、思ったように機能しません。

{'sections': [{'id': 11, 'info': 'This is section ONE', 'tag': 's1'},
              {'fields': [{'id': 15,
                           'info': 'This is field ONE',
                           'tag': 'f1'},
                          {'elements': [{'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e1',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e2',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e3',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e4',
                                         'type_of': 'text_field'}],
                           'id': 16,
                           'info': 'This is field TWO',
                           'tag': 'f2'},
                          {'elements': [{'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e5',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e6',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element',
                                         'tag': 'e7',
                                         'type_of': 'text_field'},
                                        {'id': 20,
                                         'info': 'This is element ONE',
                                         'tag': 'e8',
                                         'type_of': 'text_field'}],
                           'id': 16,
                           'info': 'This is field THREE',
                           'tag': 'f3'}],
               'id': 12,
               'info': 'This is section TWO',
               'tag': 's2'},
              {'fields': [{'id': 15,
                           'info': 'This is field FOUR',
                           'tag': 'f4'},
                          {'id': 15,
                           'info': 'This is field FIVE',
                           'tag': 'f5'},
                          {'id': 15,
                           'info': 'This is field SIX',
                           'tag': 'f6'}],
               'id': 12,
               'info': 'This is section THREE',
               'tag': 's3'}],
 'tag': 'test'}

私がやりたいことは、レベル 1 のすべてのアイテムに番号が付けられ、次にレベル 2 のすべてのアイテムに番号が付けられ、次にレベル 3、次にレベル 4 に番号が付けられることです。この場合、メイン アイテムに 1 の ID を指定し、次にセクションを 2、3、4 として識別し、次にフィールドを 5 として識別し、次に要素などを識別します。開始しますが、かなり間違っています。

編集:私が本当に必要なのは、ネストされた辞書構造から親/子ノードのツリーを作成して、必要に応じてこのツリーのアイテムを反復/挿入/取得/操作できるようにすることです。それを行う簡単な方法はありますか?思った以上に頑張っているようです。

EDIT2:元の質問に対する解決策を見つけました。ID を追加する余分な手順の代わりに、組み込みの id() 関数を使用することにしたところ、必要な最小限のツリーを作成できましたが、これはまだ演習として役立ちます。

4

4 に答える 4

0

count変数をitertools.countイテレータに置き換えるソリューションは次のとおりです。

from itertools import count
def r(y):
    counter = count()
    def recurse(y, counter):
        for i in y.iteritems():
            i['id'] = next(counter)
            for k,v in y.iteritems():
                if isinstance(v, list):
                    [recurse(i, counter) for i in v]
                else:
                    pass
    recurse(y, counter)
    return y

itertools.count()は、next()が呼び出されるたびに次の整数を返すジェネレーターを作成します。これを再帰関数に渡して、重複するIDが作成されないようにすることができます。

于 2012-09-26T16:38:16.310 に答える
0

さて、深さと親を使用して ID を設定するソリューションがあります。

>>> def decorate_tree(tree, parent=None, index=None):
    global ID
    if type(tree) == type({}):
        if parent is None:
            parent = '1'
            tree['id'] = parent
        else:
            tree['id'] = '{0}.{1}'.format(parent, index)
        if 'info' in tree:
            print tree['info'], '=>', tree['id']
        child_index = 1
        for key in tree:
            if type(tree[key]) == type([]):
                for item in tree[key]:
                    decorate_tree(item, tree['id'], child_index)
                    child_index += 1


>>> decorate_tree(d)
This is section ONE => 1.1
This is section TWO => 1.2
This is field ONE => 1.2.1
This is field TWO => 1.2.2
This is element => 1.2.2.1
This is element => 1.2.2.2
This is element => 1.2.2.3
This is element => 1.2.2.4
This is field THREE => 1.2.3
This is element => 1.2.3.1
This is element => 1.2.3.2
This is element => 1.2.3.3
This is element ONE => 1.2.3.4
This is section THREE => 1.3
This is field FOUR => 1.3.1
This is field FIVE => 1.3.2
This is field SIX => 1.3.3
>>> from pprint import pprint
>>> pprint(d)
{'id': '1',
 'sections': [{'id': '1.1', 'info': 'This is section ONE', 'tag': 's1'},
              {'fields': [{'id': '1.2.1',
                           'info': 'This is field ONE',
                           'tag': 'f1'},
                          {'elements': [{'id': '1.2.2.1',
                                         'info': 'This is element',
                                         'tag': 'e1',
                                         'type_of': 'text_field'},
                                        {'id': '1.2.2.2',
                                         'info': 'This is element',
                                         'tag': 'e2',
                                         'type_of': 'text_field'},
                                        {'id': '1.2.2.3',
                                         'info': 'This is element',
                                         'tag': 'e3',
                                         'type_of': 'text_field'},
                                        {'id': '1.2.2.4',
                                         'info': 'This is element',
                                         'tag': 'e4',
                                         'type_of': 'text_field'}],
                           'id': '1.2.2',
                           'info': 'This is field TWO',
                           'tag': 'f2'},
                          {'elements': [{'id': '1.2.3.1',
                                         'info': 'This is element',
                                         'tag': 'e5',
                                         'type_of': 'text_field'},
                                        {'id': '1.2.3.2',
                                         'info': 'This is element',
                                         'tag': 'e6',
                                         'type_of': 'text_field'},
                                        {'id': '1.2.3.3',
                                         'info': 'This is element',
                                         'tag': 'e7',
                                         'type_of': 'text_field'},
                                        {'id': '1.2.3.4',
                                         'info': 'This is element ONE',
                                         'tag': 'e8',
                                         'type_of': 'text_field'}],
                           'id': '1.2.3',
                           'info': 'This is field THREE',
                           'tag': 'f3'}],
               'id': '1.2',
               'info': 'This is section TWO',
               'tag': 's2'},
              {'fields': [{'id': '1.3.1',
                           'info': 'This is field FOUR',
                           'tag': 'f4'},
                          {'id': '1.3.2',
                           'info': 'This is field FIVE',
                           'tag': 'f5'},
                          {'id': '1.3.3',
                           'info': 'This is field SIX',
                           'tag': 'f6'}],
               'id': '1.3',
               'info': 'This is section THREE',
               'tag': 's3'}],
 'tag': 'test',
 'type_of': 'custom'}
>>> 

したがって、ID 1.3.4 の親は ID 1.3、兄弟は ID 1.3.x、子は 1.3.4.x です。このように、取得と挿入はそれほど難しくありません (シフト インデックス)。

于 2012-09-26T15:51:46.740 に答える
0

考慮すべき代替案は、双方向リンク リストです。例えば:

Index  Tag     Parent  Children        Info
0      test    -1      [s1,s2,s3]      ""
1      s1      0       []              "This is section ONE"
2      s2      0       [f1,f2,f3]      "This is section TWO"
3      f1      2       []              "This is field ONE"
4      f2      2       [e1,e2,e3,e4]   "This is field TWO"
5      e1      4       []              "This is element"
6      e2      4       []              "This is element"
       .
       .
       .

これは概念的な表現です。実際の実装では、タグの代わりに子列に数値の行インデックスを使用します。これは、入力データがダーティで、タグが重複または欠落している可能性があり、タグに依存する構造を構築したくないためです。ユニークであること。追加の列は簡単に追加できます。

ツリーを再帰的にたどってテーブルを作成しますが、フラット テーブル (リストの 2D リスト) の行を使用して参照することで、ツリー内の項目を操作する方が簡単な場合があります。

編集:これは、構造化された情報(タグ、親、子など)を各ノードに追加する元の質問(ノードの装飾されていないリスト)に対するソリューションの拡張です。これは、ツリーを上下に移動する必要がある場合に役立ちます。

編集:このコード:

def recurse(y, n=[], p=-1):
    node = ["", p, [], "", ""]   # tag, parent, children, type, info
    vv = []
    for k,v in y.items():
        if k == "tag":
            node[0] = v
        elif k == "info":
            node[4] = v
        elif isinstance(v, list):
            node[3] = k
            vv = v
    n.append(node)
    p = len(n)-1
    for i in vv:
        n[p][2].append(len(n))
        n = recurse(i, n, p)
    return(n)

nodes = recurse(a)
for i in range(len(nodes)):
    print(i, nodes[i])

生成します(読みやすくするために手動で列に間隔を空けます):

 0 ['test', -1, [1, 2, 14],     'sections',   '']
 1 [  's1',  0, [],             '',           'This is section ONE']
 2 [  's2',  0, [3, 4, 9],      'fields',     'This is section TWO']
 3 [  'f1',  2, [],             '',           'This is field ONE']
 4 [  'f2',  2, [5, 6, 7, 8],   'elements',   'This is field TWO']
 5 [  'e1',  4, [],             '',           'This is element']
 6 [  'e2',  4, [],             '',           'This is element']
 7 [  'e3',  4, [],             '',           'This is element']
 8 [  'e4',  4, [],             '',           'This is element']
 9 [  'f3',  2, [10, 11, 12, 13], 'elements', 'This is field THREE']
10 [  'e5',  9, [],             '',           'This is element']
11 [  'e6',  9, [],             '',           'This is element']
12 [  'e7',  9, [],             '',           'This is element']
13 [  'e8',  9, [],             '',           'This is element ONE']
14 [  's3',  0, [15, 16, 17],   'fields',     'This is section THREE']
15 [  'f4', 14, [],             '',           'This is field FOUR']
16 [  'f5', 14, [],             '',           'This is field FIVE']
17 [  'f6', 14, [],             '',           'This is field SIX']
于 2012-09-26T17:13:57.773 に答える