Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中使用键的有序列表遍历带列表的嵌套字典_Python_Tree - Fatal编程技术网

在Python中使用键的有序列表遍历带列表的嵌套字典

在Python中使用键的有序列表遍历带列表的嵌套字典,python,tree,Python,Tree,我有一个嵌套的dict,如下所示: d = {'A': [{'B': [{'C': [{'D1':[]}, {'D2': []}]}]}]} # just an example 我得到的列表/路径如下: l = ['A','B','C','D1'] from copy import deepcopy def walk_dict(ld, path): if isinstance(path, str): path = path.split() t = deepc

我有一个嵌套的
dict
,如下所示:

d = {'A': [{'B': [{'C': [{'D1':[]}, {'D2': []}]}]}]} # just an example
我得到的列表/路径如下:

l = ['A','B','C','D1']
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()
我想沿着
dict
中的路径,检索
D1
的对应值。为此,我编写了以下程序:

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)
def find_dict(ld,key):
#我们可以假设'ld'有dict,每个dict都有唯一的密钥
对于ld中的d:
如果钥匙不在d中:
持续
返回d
def步行指令(d,路径):
温度=无
对于枚举(路径)中的i,n:
如果i==0:
温度=d.get(n)
elif i<(透镜(路径)-1):
温度=查找目录(温度,n)
温度=温度获取(n)
其他:#最后一项
温度=查找目录(温度,n)
打印('找到了!')
打印(i,n)
打印(临时获取(n))
返回温度获取(n)
d={'A':[{'B':[{'C':[{'D1':[]},{'D2':[]}]}
l=['A'、'B'、'C'、'D1']#成功检索到'D1'的值
步行(d,l)
l=['A'、'B'、'C'、'D2']#成功检索到'D2'的值
步行(d,l)
l=['A'、'B'、'C'、'D3']#按预期获取非类型错误,因为'D3'不存在
步行(d,l)
我想知道是否有更好的方法来实现这一点。我觉得这种方法有点过于冗长,甚至可能有bug潜伏


提前感谢您的回答/建议

像这样走路怎么样:

l = ['A','B','C','D1']
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()
输出:

['values of D1']
I'm D2
None
None
all cases passed

我使用了递归方法

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)
产出:

l = ['A','B','C','D1']
# xyz
l = ['A','B','C']
# [{'D1': 'xyz'}, {'D2': []}]
l = ['A','B','C','D3']
# None
l = ['A','B','C','D2']
# []

可以使用此递归函数:

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')
输出:

['values of D1']
I'm D2
None
None
all cases passed
以下是当前答案的时间安排。计时和输入设置的源代码可以作为要点找到


这看起来是一种更清洁的解决方案。:)你为什么要做一份临时记录的浅显副本?另一个后续问题:如果我想在
D2
中添加另一个字符串,比如说,
“我是D2的兄弟”
,这样它就会反映在
d
(source
dict
)中,进行浅拷贝会影响吗?谢谢你的帮助!对于那些想使用列表而不是字符串作为路径的人,我分享了Waket的解决方案@user1330974的一个稍微修改过的代码,我用
deepcopy
编辑了答案。感谢你提供了一个简洁的递归解决方案!我很少在编码时想到递归方法,因为对我来说,很难想象它们。但我知道它们很简洁:)我仍在等待其他人插话,但根据时间安排,韦克特的回答比你的答案快了几分钟,他的回答也正确。所以我可以接受他的回答。希望你不介意。:)如果您对每个答案的性能感兴趣,我在下面的答案中添加了计时。非常感谢您不厌其烦地提供运行时分析!今天我从你那里学到了如何做一个快速而酷的运行时测试。因为它很酷,我把它存档在Wayback机器中。:)@user1330974很高兴为您提供帮助!