[英]Traversing and modifying a tree-like list of dict structure
我有一個看起來像這樣的結構:
[ {'id': 4, 'children': None},
{'id': 2, 'children':
[ {'id': 1, 'children':
[ {'id': 6, 'children': None},
{'id': 5, 'children': None} ]
},
{'id': 7, 'children':
[ {'id': 3, 'children': None} ]
}
]
}
]
我還有一個選定的ID列表, [4, 5, 6, 7]
。 我想遍歷列表,並且對於列表中的每個對象,如果選中,則添加值為1
的selected
鍵,如果不是,則添加0
。
目前我正在使用此函數遞歸執行此操作:
def mark_selected(tree, selected):
for obj in tree:
obj['selected'] = 1 if obj['id'] in selected else 0
if obj['children'] is not None:
obj['children'] = mark_selected(obj['children'], selected)
return tree
這似乎工作正常,但我想知道是否有更聰明的方法來做到這一點,可能使用列表理解或生成器。
任何人都可以為此提出更優雅的解決方案嗎?
遞歸非常優雅。 列表推導不適用,因為您正在改變結構,而不是生成新的序列。 對於生成器,您可以編寫DFS或BFS遍歷器。
def dfs(nodes):
if nodes is not None:
for node in nodes:
yield node
for child in dfs(node['children']):
yield child
for node in dfs(tree):
if node['id'] in selected:
node['selected'] = true
如果要選擇的ID列表很大,那么將ID轉換為具有ID作為鍵的dict將更加高效,這將加速查找( node['id'] in selected
)。
selected = dict(zip(selected, selected))
由於您通過修改輸入對象來操作,並且由於對象在Python中具有引用語義,因此您無需在遞歸步驟中返回值或使用返回值。 此外,如果您可以用'[]'替換子項的'None'條目(更好的是,使用整個而不是列表中的元組),那么您可以簡化邏輯 - 您根本不需要基本情況,那么,因為你可以遞歸到一個“空樹”,它只會為所有零項運行for循環,即什么都不做 - 這就是你想要的。
和FFS,你為什么不使用Python的內置布爾類型?
def mark_selected(tree, selected):
for obj in tree:
obj['selected'] = obj['id'] in selected
mark_selected(obj['children'], selected)
(哦,你甚至需要按照特定的順序保留孩子嗎?有一個包含'id'鍵的dicts列表是不自然的;有一個dict,其中鍵是id,更有意義值是沒有'id'的dicts。)
我喜歡使用閉包來表示遞歸函數,對於這個例子它並不重要,但你可以節省在遞歸調用中傳遞'selected'的需要。 在更復雜的示例中,您可以在包含函數中保留相當多的狀態以供遞歸使用。
def mark_selected(tree, selected):
def recur(tree):
for obj in tree:
obj['selected'] = 1 if obj['id'] in selected else 0
if obj['children'] is not None:
recur(obj['children'])
recur(tree)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.