[英]Providing an id for each recursed item in nested dictionary of lists of dictionaries
我正在使用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.