我在Python中有一个JSON对象,表示为嵌套的字典列表。 (字典的某些值本身就是字典,依此类推。)
我希望能够在这个嵌套字典结构的所有分支上搜索一个键 当我找到密钥时,我希望能够返回通向它的完整密钥路径。
例如:我正在寻找具有“特殊地址密钥”的“特殊代理”,但并非所有特殊代理都拥有它,并且那些确实在其JSON中的不一致路径中拥有它。
所以我搜索关键Special Address code
。
结果应该返回:
/'People'/'SpecialAgents'/'007'/'Special Address code'/
所以我将能够以这种方式获得其信息:
json_obj['People']['SpecialAgents']['007']['Special Address code']
请注意,这与this question类似,但我需要找到所有密钥实例的完整路径。
答案 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"