簡體   English   中英

為字典列表的嵌套字典中的每個遞歸項目提供一個ID

[英]Providing an id for each recursed item in nested dictionary of lists of dictionaries

擴展: 遞歸字典列表等的字典(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'}

我想發生的是,第一層中的所有項目都已編號,然后第二層中的所有項目都已編號,然后是第三層,然后是第四層。 在這種情況下,應為主項設置id為1,然后將各部分標識為2,3,4,然后將字段標識為5,然后是元素,依此類推。睡覺后回頭看一看,我可以看到它是開始,但完全錯誤。

編輯:我真正需要做的是從嵌套的字典結構中創建一個父/子節點樹,以便我可以根據需要迭代/插入/獲取/使用該樹中的項目。 有快速的方法嗎? 我似乎正在做比預期更多的工作。

EDIT2:我找到了原始問題的解決方案。 我只是決定使用內置的id()函數,而不是添加ID的額外步驟,並且能夠創建所需的最小樹,但這仍然是一個有用的練習。

因為count變量是本地變量,所以您獲得重復的ID,並且一旦recurse函數退出,對它的任何更改都將丟失。 您可以通過聲明一個全局變量來解決它,但是由於您沒有使用recurse的返回值,因此可以改用它:

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

編輯:剛意識到您正在尋找ID的廣度優先分配...這將無法實現,但是我將留下答案,因為它可能對您入門有所幫助。

好吧,我有一個使用深度和父級來設置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 ...這樣,檢索和插入就不會太困難(移位索引)。

這是一個用itertools.count迭代器替換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。

要考慮的替代方法是雙向鏈接列表。 例如:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM