[英]Walking down nested dictionary with list using an ordered list of keys in Python
I have a nested dict
as follow: 我有一个嵌套的
dict
,如下所示:
d = {'A': [{'B': [{'C': [{'D1':[]}, {'D2': []}]}]}]} # just an example
And I am given a list/path like this: 我得到这样的列表/路径:
l = ['A','B','C','D1']
I'd like to walk down the path in the dict
to retrieve the corresponding value of D1
. 我想在
dict
沿路径检索D1
的对应值。 I have written the following program to do that: 我编写了以下程序来做到这一点:
def find_dict(ld, key):
# we can assume that 'ld' has dicts each of which has unique key
for d in ld:
if key not in d:
continue
return d
def walk_dict(d,path):
temp = None
for i,n in enumerate(path):
if i == 0:
temp = d.get(n)
elif i < (len(path)-1):
temp = find_dict(temp, n)
temp = temp.get(n)
else: # last item
temp = find_dict(temp, n)
print('Found it!')
print(i,n)
print(temp.get(n))
return temp.get(n)
d = {'A': [{'B': [{'C': [{'D1':[]}, {'D2': []}]}]}]}
l = ['A','B','C','D1'] # successfully retrieved the value of 'D1'
walk_dict(d,l)
l = ['A','B','C','D2'] # successfully retrieved the value of 'D2'
walk_dict(d,l)
l = ['A','B','C','D3'] # get NoneType error as expected because 'D3' does not exist
walk_dict(d,l)
I'd like to know if there's a better way to accomplish this. 我想知道是否有更好的方法可以做到这一点。 I feel like this approach has a bit too verbose, and maybe even have bug(s) lurking.
我觉得这种方法太冗长了,甚至可能还潜伏着错误。
Thank you in advance for your answers/suggestions! 预先感谢您的回答/建议!
I have used a recursive approach. 我使用了递归方法。
d = {'A': [{'B': [{'C': [{'D1':'xyz'}, {'D2': []}]}]}]}
l = ['A','B','C','D1']
output = []
def find_path(dict_obj,key=0):
for k,v in dict_obj.items():
if k == l[key]:
if key == len(l)-1:
output.append(v)
return
if isinstance(v,dict):
find_path(v, key+1)
elif isinstance(v,list):
for i,item in enumerate(v):
if isinstance(item,dict):
find_path(item,key+1)
find_path(d)
print(output[0] if output else None)
Outputs: 输出:
l = ['A','B','C','D1']
# xyz
l = ['A','B','C']
# [{'D1': 'xyz'}, {'D2': []}]
l = ['A','B','C','D3']
# None
l = ['A','B','C','D2']
# []
How about walk the dict like this: 如何像这样走动字典:
from copy import deepcopy
def walk_dict(ld, path):
if isinstance(path, str):
path = path.split()
t = deepcopy(ld)
for key in path:
if isinstance(t, list):
try:
t = [d for d in t if key in d][0]
except IndexError:
return
try:
t = t[key]
except KeyError:
return
else:
return t
def main():
d = {'A': [{'B': [{'C': [{'D1':['values of D1']}, {'D2': "I'm D2"}]}]}]}
a = 'A B C D1'
print(walk_dict(d, a))
a = 'A B C D2'
print(walk_dict(d, a))
a = 'A B C D3'
print(walk_dict(d, a))
a = 'A B1 C D3'
print(walk_dict(d, a))
if __name__ == '__main__':
main()
Output: 输出:
['values of D1']
I'm D2
None
None
You can use this recursive function: 您可以使用此递归函数:
d = {'A': [{'B': [{'C': [{'D1':[]}, {'D2': []}]}]}]} # just an example
def walk(_d, path):
a, *b = path
if isinstance(_d, list):
_d = [i for i in _d if a in i]
if not _d:
return None
_d = _d[0]
return _d[a] if not b else walk(_d[a], b)
tests = [[['A','B','C','D1'], []], [['A','B','C','D2'], []], [['A','B','C','D3'], None]]
for a, b in tests:
assert walk(d, a) == b
print('all cases passed')
Output: 输出:
all cases passed
Below are the timings for the current answers. 以下是当前答案的时间安排。 The source code for the timings and input setup can be found as a gist here .
时序和输入设置的源代码可以在这里找到要点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.