在Python中像字典一样在树中遍历

时间:2019-03-06 14:14:33

标签: python dictionary

我有一本这样的字典:

{'A': [12343,
  2342349,
  {'B': [3423,
    342349283,
    73,
    {'C': [-23,
      -2342342,
      36],
     'D': [-2,
      -2520206,
      63]}],
   'E': [-1.5119711426000446,
    -1405627.5262916991,
    26.110728689275614,
    {'F': [-1.7211282679440503,
      -1601770.8149339128,
      113.9541439658396],
     'G': [0.21282003105839883,
      196143.28864221353,
      -13.954143965839597,
      {'H': [0.43384581412426826,
        399408,
        203],
       'I': [-0.22,
        -203265,
        -103]}]}]}]}

我想要一个可以获取值的函数。 例如traverse(dictionary,'F'),它应该给我输出。找不到任何解决方案。我能够遍历1或2个级别,但不能更多。代码要么会中断,要么不会停止。

我当前无法使用的解决方案是:

def traverse(dictionary,search):
    print "Traversing"
    if isinstance(dictionary,dict):
        keys = dictionary.keys()
        print keys
        if search in keys:
            print "Found",search,"in",keys
            print "Printing found dict",dictionary
            print
            print "Check this out",dictionary.get(search)
            print "Trying to return"
            val=dictionary.get(search)
            return val
        else:
            for key in keys:
                print 'Key >>>>>>>>>',dictionary.get(key)
                print
                temp=dictionary.get(key)[-1]
                print "Temp >>>>>>>",temp
                traverse(temp,search)

2 个答案:

答案 0 :(得分:1)

您需要同时处理字典和列表,才能完全遍历您的结构。您目前仅处理字典,但是其中带有'F'键的字典是列表对象的元素,因此您无法使用方法找到它。

虽然您可以使用递归来利用函数调用堆栈来跟踪结构的不同级别,但我还是要反复进行并使用列表或collections.deque()(更快这项工作)来跟踪仍要处理的对象。这样效率更高,并且不会遇到较大结构的递归深度错误。

例如,使用生成器函数遍历所有元素,然后产生每个访问的元素,可能是:

from collections import deque

def walk(d):
    queue = deque([d])
    while queue:
        elem = queue.popleft()
        if isinstance(elem, dict):
            queue.extend(elem.values())
        elif isinstance(elem, list):
            queue.extend(elem)
        yield elem

以上使用队列先处理元素呼吸;要将其用作堆栈,只需将queue.popleft()替换为queue.pop()

然后您可以使用上面的助行器找到您的元素:

def search_key(obj, key):
    for elem in walk(obj):
        if isinstance(elem, dict) and key in elem:
            return elem

对于您的字典,上面的代码返回包含查找键的第一个字典:

>>> search_key(dictionary, 'F')
{'F': [-1.7211282679440503, -1601770.8149339128, 113.9541439658396], 'G': [0.21282003105839883, 196143.28864221353, -13.954143965839597, {'H': [0.43384581412426826, 399408, 203], 'I': [-0.22, -203265, -103]}]}
>>> _['F']
[-1.7211282679440503, -1601770.8149339128, 113.9541439658396]

如果您只对给定键的值感兴趣,请当然将其返回:

def search_key(obj, key):
    for elem in walk(obj):
        if isinstance(elem, dict) and key in elem:
            return elem[key]

答案 1 :(得分:1)

假设在任何给定的数据结构中只有一个匹配的键,则可以使用一个函数来递归地遍历字典以查找键并返回其值(如果找到),如果找不到,则会引发异常,以便调用框架可以捕获它并移至下一个候选键:

def traverse(dictionary, search):
    for k, v in dictionary.items():
        if k == search:
            return v
        if isinstance(v[-1], dict):
            try:
                return traverse(v[-1], search)
            except ValueError:
                pass
    raise ValueError("Key '%s' not found" % search)

以便traverse(d, 'F')返回(假设您的字典存储为变量d):

[-1.7211282679440503, -1601770.8149339128, 113.9541439658396]

另一方面,如果给定数据中可以有多个匹配项,则可以使函数产生匹配键的值,从而使该函数成为生成器,生成0到许多匹配键的子列表:

def traverse(dictionary, search):
    for k, v in dictionary.items():
        if k == search:
            yield v
        if isinstance(v[-1], dict):
            yield from traverse(v[-1], search)

使list(traverse(d, 'F'))返回:

[[-1.7211282679440503, -1601770.8149339128, 113.9541439658396]]