【问题标题】:Search value in tree of dicts in python在python中的dicts树中搜索值
【发布时间】:2013-04-23 15:46:39
【问题描述】:

我有一个巨大的字典,里面有很多嵌套的字典——就像一棵巨树,深度未知。

我需要一个函数,类似于find_value(),它接受dict、value(作为字符串),并返回list of lists,每个都是“路径”(从第一个键到具有找到值的键(或键值)的顺序键链)。如果没有找到,则返回空列表。

我写了这段代码:

def find_value(dict, sought_value, current_path, result):   
    for key,value in dict.items():
        current_path.pop()
        current_path.append(key)
        if sought_value in key:
            result.append(current_path)
        if type(value) == type(''):
            if sought_value in value:
                result.append(current_path+[value])
        else:
            current_path.append(key) 
            result = find_value(value, sought_value, current_path, result)
    current_path.pop()
    return result 

我调用这个函数来测试:

result = find_value(self.dump, sought_value, ['START_KEY_FOR_DELETE'], [])
if not len(result):
    print "forgive me, mylord, i'm afraid we didn't find him.."
elif len(result) == 1:
    print "bless gods, for all that we have one match, mylord!"

由于一些莫名其妙的原因,我对这个函数的实现未能通过我的一些测试。我开始调试并发现,即使 current_path 打印正确的东西(它总是这样,我检查了!),结果被莫名其妙地损坏了。也许是因为递归魔法?

谁能帮我解决这个问题?也许我的任务有一个简单的解决方案?

【问题讨论】:

  • 为什么更喜欢非递归?您是否期望树的深度如此之深以至于您担心堆栈溢出?
  • 事情是,如果你的树没有一些属性,你将不得不扫描它。恕我直言,你的函数有点矫枉过正,因为它是递归的,它试图用堆栈模拟递归。你应该选择一个 :) 见 here 进行仿真
  • 这应该是递归的
  • 您要我为您调试还是正式证明正确性?
  • 我不知道为什么,但我现在不想做这两件事。我只能给你一个建议——睁大你的眼睛!递归很酷! ;)

标签: python algorithm search dictionary tree


【解决方案1】:

我怀疑您可以做很多事情来优化这样的递归搜索。假设在同一个字典上有很多查找,并且字典一旦加载就不会改变,那么你可以索引它以获得 O(1) 查找...

def build_index(src, dest, path=[]):
    for k, v in src.iteritems():
        fk = path+[k]
        if isinstance(v, dict):
            build_index(v, dest, fk)
        else:
            try:
                dest[v].append(fk)
            except KeyError:
                dest[v] = [fk]

>>> data = {'foo': {'sub1': 'blah'}, 'bar': {'sub2': 'whatever'}, 'baz': 'blah'}
>>> index = {}
>>> build_index(data, index)
>>> index
{'blah': [['baz'], ['foo', 'sub1']], 'whatever': [['bar', 'sub2']]}
>>> index['blah']
[['baz'], ['foo', 'sub1']]

【讨论】:

  • 谢谢你,好心的先生,如果我以后需要性能,我一定会使用你的想法:)
【解决方案2】:

当您编写result.append(current_path) 时,您并不是在复制current_path,它会继续发生变异。将其更改为result.append(current_path[:])

【讨论】:

  • 我会被诅咒的。你找到错误了!!!!现在它通过了所有测试!你只是......上帝的美丽创造。
猜你喜欢
  • 2018-03-31
  • 2013-05-06
  • 1970-01-01
  • 1970-01-01
  • 2021-01-15
  • 2018-09-15
  • 2021-01-28
  • 2011-03-04
  • 2021-02-20
相关资源
最近更新 更多