在嵌套的 Python 字典中搜索并记录 "path"
Search in nested Python dict and record "path"
在这个 answer 的帮助下,我试图想出一个函数来搜索嵌套 Python 字典中的键并记录 "path"每场比赛。我的函数(见下文)似乎有效,但无法将结果保存在列表中(见代码输出)。我很确定困难在于 yield
命令,但我还没有弄明白。
o={
'dict1': {
'dict11': {
'entry11_1':1,
'entry11_2':2,
},
'dict12': {
'entry12_1':12,
'entry12_2':22,
},
},
'dict2': {
'dict21': {
'entry21_1':21,
}
},
}
curr_pos=[]
def gen_dict_extract(key, var):
global curr_pos
if hasattr(var,'iteritems'):
for k, v in var.iteritems():
#print curr_pos
if k == key:
yield v,curr_pos
if isinstance(v, dict):
curr_pos.append(k)
for result in gen_dict_extract(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in gen_dict_extract(key, d):
yield result
if len(curr_pos)>0:
curr_pos.pop()
result_list=[]
for ind,i in enumerate(gen_dict_extract('entry12_1',o)):
result_list.append(i)
print result_list[-1]
print result_list[-1]
输出:
(12, ['dict1', 'dict12'])
(12, [])
问题是我是一个元组对象。您需要复制 i 以避免覆盖。
import copy
result_list = []
for in ind in enumerate(gen_dict_extract('entry12_1',o)):
result_list.append(copy.deepcopy(i))
print result_list
在gen_dict_extract
中,你使用一个全局列表curr_pos
,当你找到密钥(yield v,curr_pos
)时直接yield它。但是列表是可变类型,你以后可以修改它(curr_pos.pop()
)
你在result_list中存储的只是对全局对象的引用,因此它包含循环内的期望值,但在循环结束时被清空。你应该 return 在 yield 时间做一个浅拷贝:yield v,curr_pos[:]
然后您将得到预期的结果:
(12, ['dict1', 'dict12'])
(12, ['dict1', 'dict12'])
顺便说一句,如果您想避免全局列表,您可以将列表作为可选参数传递:
def gen_dict_extract(key, var, curr_pos = None):
if curr_pos is None:
curr_pos = []
...
for result in gen_dict_extract(key, v, curr_pos):
...
for result in gen_dict_extract(key, d, curr_pos):
...
这将确保您在每次新调用时使用新列表,同时在递归时正确传递它
为了完整起见,这里是包含 Serge 建议的版本。我还做了一些额外的更改,因此该函数能够处理任何嵌套列表和字典组合。
def gen_dict_extract(key, var,curr_pos=None):
"""
key: key to search for
var: nested dict to search in
"""
#print curr_pos
if curr_pos is None:
curr_pos=[]
if hasattr(var,'iteritems'):
for k, v in var.iteritems():
curr_pos.append(k)
if k == key:
yield v,curr_pos[:]
if isinstance(v, dict):
for result in gen_dict_extract(key, v,curr_pos):
yield result
elif isinstance(v, list):
curr_pos.append(0)
for ind,d in enumerate(v):
curr_pos.pop()
curr_pos.append(ind)
for result in gen_dict_extract(key, d,curr_pos):
yield result
curr_pos.pop()
curr_pos.pop()
elif isinstance(var, list):
curr_pos.append(0)
for ind,d in enumerate(var):
curr_pos.pop()
curr_pos.append(ind)
for result in gen_dict_extract(key, d,curr_pos):
yield result
curr_pos.pop()
在这个 answer 的帮助下,我试图想出一个函数来搜索嵌套 Python 字典中的键并记录 "path"每场比赛。我的函数(见下文)似乎有效,但无法将结果保存在列表中(见代码输出)。我很确定困难在于 yield
命令,但我还没有弄明白。
o={
'dict1': {
'dict11': {
'entry11_1':1,
'entry11_2':2,
},
'dict12': {
'entry12_1':12,
'entry12_2':22,
},
},
'dict2': {
'dict21': {
'entry21_1':21,
}
},
}
curr_pos=[]
def gen_dict_extract(key, var):
global curr_pos
if hasattr(var,'iteritems'):
for k, v in var.iteritems():
#print curr_pos
if k == key:
yield v,curr_pos
if isinstance(v, dict):
curr_pos.append(k)
for result in gen_dict_extract(key, v):
yield result
elif isinstance(v, list):
for d in v:
for result in gen_dict_extract(key, d):
yield result
if len(curr_pos)>0:
curr_pos.pop()
result_list=[]
for ind,i in enumerate(gen_dict_extract('entry12_1',o)):
result_list.append(i)
print result_list[-1]
print result_list[-1]
输出:
(12, ['dict1', 'dict12'])
(12, [])
问题是我是一个元组对象。您需要复制 i 以避免覆盖。
import copy
result_list = []
for in ind in enumerate(gen_dict_extract('entry12_1',o)):
result_list.append(copy.deepcopy(i))
print result_list
在gen_dict_extract
中,你使用一个全局列表curr_pos
,当你找到密钥(yield v,curr_pos
)时直接yield它。但是列表是可变类型,你以后可以修改它(curr_pos.pop()
)
你在result_list中存储的只是对全局对象的引用,因此它包含循环内的期望值,但在循环结束时被清空。你应该 return 在 yield 时间做一个浅拷贝:yield v,curr_pos[:]
然后您将得到预期的结果:
(12, ['dict1', 'dict12'])
(12, ['dict1', 'dict12'])
顺便说一句,如果您想避免全局列表,您可以将列表作为可选参数传递:
def gen_dict_extract(key, var, curr_pos = None):
if curr_pos is None:
curr_pos = []
...
for result in gen_dict_extract(key, v, curr_pos):
...
for result in gen_dict_extract(key, d, curr_pos):
...
这将确保您在每次新调用时使用新列表,同时在递归时正确传递它
为了完整起见,这里是包含 Serge 建议的版本。我还做了一些额外的更改,因此该函数能够处理任何嵌套列表和字典组合。
def gen_dict_extract(key, var,curr_pos=None):
"""
key: key to search for
var: nested dict to search in
"""
#print curr_pos
if curr_pos is None:
curr_pos=[]
if hasattr(var,'iteritems'):
for k, v in var.iteritems():
curr_pos.append(k)
if k == key:
yield v,curr_pos[:]
if isinstance(v, dict):
for result in gen_dict_extract(key, v,curr_pos):
yield result
elif isinstance(v, list):
curr_pos.append(0)
for ind,d in enumerate(v):
curr_pos.pop()
curr_pos.append(ind)
for result in gen_dict_extract(key, d,curr_pos):
yield result
curr_pos.pop()
curr_pos.pop()
elif isinstance(var, list):
curr_pos.append(0)
for ind,d in enumerate(var):
curr_pos.pop()
curr_pos.append(ind)
for result in gen_dict_extract(key, d,curr_pos):
yield result
curr_pos.pop()