在嵌套字典和列表中查找键、值对的出现路径

Find path of occurrences of a key, value pair in nested dictionaries and lists

我得到了一个 json 结构,里面有一个字符串字典、列表、字典和字典列表。深度是任意的,但所有词典都有 "name".

的键

我需要做两件事。 1) 找到某个键​​的所有键值,我在下面使用它,但它看起来很笨重...

def find_all_keys(db, search_key):
    key_found_list = []
    for key, value in db.items():
        if key == search_key:
            key_found_list.append(value)
        elif isinstance(value, dict):
            resultsA = find_all_keys(value, search_key)
            for result in resultsA:
                key_found_list.append(result)
        elif isinstance(value, list):
            for item in value:
                if isinstance(item, dict):
                    resultsB = find_all_keys(item, search_key)
                    for result_outofnames in resultsB:
                        key_found_list.append(result_outofnames)
    return key_found_list

第二部分。

字典的每一层都有一个名为name的属性,是一个字符串。

我正在尝试查找某个名称的值,如果找到它,则查找在此之前“名称”的所有其他值。

因此,例如键 "name" 和 "value" some321 应该 return 路径列表,例如: md -> level0 -> level1 -> be -> some321

在第一次点击时填充列表似乎相对容易,但如果找到结果,我无法只填充列表。我可以采取任何好的方法吗?

下面是我多次失败的尝试之一:

def find_key_value_path(db, search_key, search_value):
    key_value_path_list = []
    for key, value in db.items():
        if key == search_key:
            print("found key: ", key)
            if value == search_value:
                print("found value in key", value, key)
                key_value_path_list.append(value)
        elif isinstance(value, dict):
            results = find_key_value_path(value, search_key)
            for result in results:
                key_value_path_list.append(result)
        elif isinstance(value, list):
            for item in value:
                if isinstance(item, dict):
                    more_results = find_key_value_path(item, search_key)
                    for another_result in more_results:
                        key_value_path_list.append(another_result)
    return key_value_path_list

抱歉添加 json 输入示例:

{
  "name": "/", 
  "device_count": 91, 
  "num_ports": 3, 
  "devices": [], 
  "childnodes": [
    {
      "name": "mm", 
      "device_count": 0, 
      "num_ports": 3, 
      "devices": [], 
      "childnodes": [
        {
          "name": "mynode", 
          "device_count": 0, 
          "num_ports": 3, 
          "devices": [], 
          "childnodes": [], 
          "type": "group"
        }
      ], 
      "type": "group"
    }, 
    {
      "name": "md", 
      "device_count": 91, 
      "num_ports": 4, 
      "devices": [], 
      "childnodes": [
        {
          "name": “level0, 
          "device_count": 91, 
          "num_ports": 4, 
          "devices": [], 
          "childnodes": [
            {
              "name": "level1”, 
              "device_count": 6, 
              "num_ports": 6, 
              "devices": [], 
              "childnodes": [
                {
                  "name": "level2”, 
                  "device_count": 2, 
                  "num_ports": 6, 
                  "devices": [
                    {
                      "name": “something1”, 
                      "longitude": "", 
                      "mac": "00:1a:1e:04:a9:d0", 
                      "num_ports": 6, 
                      "latitude": "", 
                      "type": "A7240XM"
                    }, 
                    {
                      "name": “something2”, 
                      "longitude": "", 
                      "mac": "00:1a:1e:04:aa:d0", 
                      "num_ports": 6, 
                      "latitude": "", 
                      "type": "A7240XM"
                    }
                  ], 
                  "childnodes": [], 
                  "type": "group"
                }, 
                {
                  "name": "ng", 
                  "device_count": 2, 
                  "num_ports": 6, 
                  "devices": [
                    {
                      "name": “someother1”, 
                      "longitude": "", 
                      "mac": "00:1a:1e:05:4e:b8", 
                      "num_ports": 6, 
                      "latitude": "", 
                      "type": "A7240XM"
                    }, 
                    {
                      "name": “findME, 
                      "longitude": "", 
                      "mac": "00:1a:1e:05:4d:e8", 
                      "num_ports": 6, 
                      "latitude": "", 
                      "type": "A7240XM"
                    }
                  ], 
                  "childnodes": [], 
                  "type": "group"
                }, 
                {
                  "name": “be”, 
                  "device_count": 2, 
                  "num_ports": 6, 
                  "devices": [
                    {
                      "name": “some123”, 
                      "longitude": "", 
                      "mac": "00:1a:1e:05:4e:b8", 
                      "num_ports": 6, 
                      "latitude": "", 
                      "type": "A7240XM"
                    }, 
                    {
                      "name": “some321”, 
                      "longitude": "", 
                      "mac": "00:1a:1e:05:4d:e8", 
                      "num_ports": 6, 
                      "latitude": "", 
                      "type": "A7240XM"
                    }
                  ], 
                  "childnodes": [], 
                  "type": "group"
                },

您应该使用 yield 来创建迭代器。这将使代码更简单、更高效(特别是如果您不打算总是经历所有事件)。要只找第一个,可以用next函数。

def findKeys(d,key,value):
    if key in d and d[key] == value: yield [d["name"]]
    subLevels = ( (a,v) for a,vl in d.items() if isinstance(vl,list) for v in vl )
    for attrib,subDict in subLevels:
        if not isinstance(subDict,dict):continue
        for path in findKeys(subDict,key,value):
            yield [d["name"]]+path

输出:

for path in findKeys(d,"type","A7240XM"):
    print(path)

['/', 'md', 'level0', 'level1', 'level2', 'something1']
['/', 'md', 'level0', 'level1', 'level2', 'something2']
['/', 'md', 'level0', 'level1', 'ng', 'someother1']
['/', 'md', 'level0', 'level1', 'ng', 'findME']
['/', 'md', 'level0', 'level1', 'be', 'some123']
['/', 'md', 'level0', 'level1', 'be', 'some321'] 

]

next(findKeys(d,"name","some123"))

['/', 'md', 'level0', 'level1', 'be', 'some123']