在Python 3.X中从深度嵌套的字典中打印特定键和值

13

我是Python的新手,试图搜索但似乎找不到我想要实现的示例。如果有任何想法则不胜感激。我正在使用具有许多键和值的嵌套字典,但我只想使用过滤列表变量打印特定的键和值。

my_nested_dict = {"global": {"peers": {"15.1.1.1": {"remote_id": "15.1.1.1", "address_family": {"ipv4": {"sent_prefixes": 1, "received_prefixes": 4, "accepted_prefixes": 4}}, "remote_as": 65002, "uptime": 13002, "is_enabled": true, "is_up": true, "description": "== R3 BGP Neighbor ==", "local_as": 65002}}, "router_id": "15.1.1.2"}}

我想要对它进行筛选,并选择要打印出来的键和值

filtered_list = ['peers', 'remote_id', 'remote_as', 'uptime']

并取得一个成功的成果

peers: 15.1.1.1
remote_id: 15.1.1.1
remote_as: 65002
uptime: 13002
5个回答

15

使用递归和 isinstance

my_nested_dict = {"global": {"peers": {"15.1.1.1": {"remote_id": "15.1.1.1", "address_family": {"ipv4": {"sent_prefixes": 1, "received_prefixes": 4, "accepted_prefixes": 4}}, "remote_as": 65002, "uptime": 13002, "is_enabled": True, "is_up": True, "description": "== R3 BGP Neighbor ==", "local_as": 65002}}, "router_id": "15.1.1.2"}}

filtered_list = ['peers', 'remote_id', 'remote_as', 'uptime']

def seek_keys(d, key_list):
    for k, v in d.items():
        if k in key_list:
            if isinstance(v, dict):
                print(k + ": " + list(v.keys())[0])
            else:
                print(k + ": " + str(v))
        if isinstance(v, dict):
            seek_keys(v, key_list)

seek_keys(my_nested_dict, filtered_list)
注意:此处存在一种内置假设,即如果您想要从值是另一个字典的键中获取“值”,则会获取第一个键。

注意:此处存在一种内置假设,即如果您想要从值是另一个字典的键中获取“值”,则会获取第一个键。


嗨,Jacob,我尝试了那个代码,但是我得到了以下错误:TypeError:'dict_keys'对象不支持索引。 - JHCTac
太棒了,@U9-Forward和@JacobIRR!那正是我要找的。 - JHCTac
1
@JHCTac 很高兴能够帮忙。 - U13-Forward

0
除了@JacobIRR的回答之外,我建议您尝试将递归数据缓存到一个扁平的字典中。这样,它比每次递归都要快得多。您不必担心内存问题,因为扁平字典中的值只是指向深层次字典中原始对象的引用。我会把修改JacobIRR代码的任务留给您 :)。

0
@JacobIRR发表了一个很棒的答案,但由于您正在尝试将匹配的键与其对应的值连接起来,因此出现了一个更短的解决方案:
my_nested_dict = {"global": {"peers": {"15.1.1.1": {"remote_id": "15.1.1.1", "address_family": {"ipv4": {"sent_prefixes": 1, "received_prefixes": 4, "accepted_prefixes": 4}}, "remote_as": 65002, "uptime": 13002, "is_enabled": True, "is_up": True, "description": "== R3 BGP Neighbor ==", "local_as": 65002}}, "router_id": "15.1.1.2"}}
_list = ['peers', 'remote_id', 'remote_as', 'uptime']

def _join(a, b):
  return '{}:{}\n'.format(a, _keys(b, True) if isinstance(b, dict) else b)

def _keys(_d, flag = False):
  return ''.join(_join(a, b) if a in _list else (a+'\n' if flag else '')+_keys(b) 
          for a, b in _d.items())

print(get_keys(my_nested_dict))

输出:

peers:15.1.1.1
remote_id:15.1.1.1
remote_as:65002
uptime:13002

0
在 Python 3 中,使用生成器而不是递归更高效、更简单:
from typing import Any, Tuple, Generator, FrozenSet

def search_in_dict(d: Any, keys: FrozenSet[str]) -> Generator[Tuple[str, Any], None, None]:
    """
    Generate pairs key-value for found keys
    """
    if not isinstance(d, dict):
        return
    for key, value in d.items():
        if key in keys:
            if isinstance(value, dict):
                # Special case: return the first key from nested dict as value
                yield key, tuple(value.keys())[0]
            else:
                yield key, value
        # continue to search deeper
        yield from search_in_dict(value, keys)

然后再将其折叠成字典:

flatten_dict_with_results = dict(kv for kv in search_in_dict(my_nested_dict, keys=frozenset(filtered_list)))

0
你可以使用jsonparse_ng(pip install jsonparse-ng)。没有if/else语句,"peers"键的值会像原样(一个字典)打印出来。
from jsonpath_ng.ext import parse

my_nested_dict = {
    "global": {
        "peers": {
            "15.1.1.1": {
                "address_family": {
                    "ipv4": {
                        "accepted_prefixes": 4,
                        "received_prefixes": 4,
                        "sent_prefixes": 1
                    }
                },
                "description": "== R3 BGP Neighbor ==",
                "is_enabled": true,
                "is_up": true,
                "local_as": 65002,
                "remote_as": 65002,
                "remote_id": "15.1.1.1",
                "uptime": 13002
            }
        },
        "router_id": "15.1.1.2"
    }
}
filtered_list = ['peers', 'remote_id', 'remote_as', 'uptime']

for list_item in filtered_list:
found = parse(f'$..{list_item}').find(my_nested_dict)
if found:
    if list_item == 'peers':
        print(f'{list_item} - {"".join(found[0].value.keys())}')
    else:
        print(f'{list_item} - {found[0].value}')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接