在嵌套字典中搜索键

时间:2015-07-25 10:04:47

标签: python

我在Python中有一个JSON对象,表示为嵌套的字典列表。 (字典的某些值本身就是字典,依此类推。)

我希望能够在这个嵌套字典结构的所有分支上搜索一个键 当我找到密钥时,我希望能够返回通向它的完整密钥路径。

例如:我正在寻找具有“特殊地址密钥”的“特殊代理”,但并非所有特殊代理都拥有它,并且那些确实在其JSON中的不一致路径中拥有它。

所以我搜索关键Special Address code。 结果应该返回:

/'People'/'SpecialAgents'/'007'/'Special Address code'/  

所以我将能够以这种方式获得其信息:

json_obj['People']['SpecialAgents']['007']['Special Address code']

请注意,这与this question类似,但我需要找到所有密钥实例的完整路径。

2 个答案:

答案 0 :(得分:11)

您需要进行递归搜索。

您可以定义一个函数来深入搜索输入json:

True

然后我们可以在此similar SO question中使用示例JSON来测试递归搜索:

def find_in_obj(obj, condition, path=None):

    if path is None:
        path = []    

    # In case this is a list
    if isinstance(obj, list):
        for index, value in enumerate(obj):
            new_path = list(path)
            new_path.append(index)
            for result in find_in_obj(value, condition, path=new_path):
                yield result 

    # In case this is a dictionary
    if isinstance(obj, dict):
        for key, value in obj.items():
            new_path = list(path)
            new_path.append(key)
            for result in find_in_obj(value, condition, path=new_path):
                yield result 

            if condition == key:
                new_path = list(path)
                new_path.append(key)
                yield new_path 

让我们找到密钥的所有实例' id'并返回让我们到达那里的完整路径:

In [15]: my_json = { "id" : "abcde",
   ....:   "key1" : "blah",
   ....:   "key2" : "blah blah",
   ....:   "nestedlist" : [ 
   ....:     { "id" : "qwerty",
   ....:       "nestednestedlist" : [ 
   ....:         { "id" : "xyz",
   ....:           "keyA" : "blah blah blah" },
   ....:         { "id" : "fghi",
   ....:           "keyZ" : "blah blah blah" }],
   ....:       "anothernestednestedlist" : [ 
   ....:         { "id" : "asdf",
   ....:           "keyQ" : "blah blah" },
   ....:         { "id" : "yuiop",
   ....:           "keyW" : "blah" }] } ] } 

答案 1 :(得分:3)

您需要搜索树。这是最简单的方法。

可以增强 - 例如,最好使用None作为默认arg值而不是某个对象。此外,这是深度优先搜索 - 您可能只想获得一个结果,并且当宽度优先搜索更好时(如果您不知道它们,请阅读维基百科上的这两个术语)。

import json

example_json = """{
 "someList" : [
  {
   "x": {
    "y": {
     "z": "Some value"
    }
   }
  }, 
  {
   "x": {
    "y": {
     "a": "Wrong key"
    }
   }
  }
 ]
}
"""

struct = json.loads(example_json)

def find_all_with_key(wanted_key, tree, path=tuple()):
    if isinstance(tree, list):
        for idx, el in enumerate(tree):
            yield from find_all_with_key(wanted_key, el, path+(idx,))
    elif isinstance(tree, dict):
        for k in tree:
            if k == wanted_key:
                yield path +(k, )
        # you can add order of width-search by sorting result of tree.items()
        for k, v in tree.items(): 
            yield from find_all_with_key(wanted_key, v, path+(k,))

def retrieve(tree, path):
    for p in path:
        tree = tree[p]
    return tree

result = list(find_all_with_key("z", struct))
expected = [ ("someList", 0, "x", "y", "z") ]

assert result == expected
assert retrieve(struct, result[0]) == "Some value"