在嵌套Dict中递归查找路径

时间:2019-02-05 02:52:26

标签: python dictionary recursion

我有一个嵌套的字典:

d = {
 "@timestamp": "2019-01-08T19:33:50.066Z",
 "metricset": {
    "rtt": 2592,
    "name": "filesystem",
    "module": "system"
 },
 "system": {
    "filesystem": {
        "free_files": 9660022,
        "type": "rootfs",
        "device_name": "rootfs",
        "available": 13555355648,
        "files": 9766912,
        "mount_point": "/",
        "total": 19992150016,
        "used": {
            "pct": 0.322,
            "bytes": 6436794368
        },
        "free": 13555355648
    }
 },
 "host": {
    "name": "AA"
 },
 "beat": {
    "name": "AA",
    "hostname": "AA",
    "version": "6.3.2"
  }
}

我想做的就是将此字典写入CSV文件。我希望csv的标头是这样的:

system.filesystem.type

其中,路径由每个句点(由句点分隔)组成。我能够浏览字典并获得所需的大多数标题。但是我的问题是重复值。

问题:我递归地通过dict并获取所有值并将它们放在列表中。然后,我再次在字典中搜索这些值,但是这次保存了构造标头的路径。但是,使用重复的值(即值“ rootfs”),我只得到返回的第一个键值(“ type”:“ rootfs”)。

这是我遍历该字典的所有值的方法,这正是我想要的:

def traverse(valuelist, dictionary):

    for k,v in dictionary.items():

       if isinstance(v, dict):
         traverse(valuelist,v)
       else:
         valuelist.append(v)

    return valuelist

现在这是从上面的代码中获取每个值的路径的代码:

def getpath(nested_dict, value, prepath=()):
    for k,v in nested_dict.items():
        path = prepath + (k,)
        if v == value: # found value
           return path
        elif hasattr(v, 'items'): # v is a dict
            p = getpath(v, value, path) # recursive call
            if p is not None:
                return p

这不是我自己的代码。我在SO上找到了它,并想对其进行修改以获取重复值的每个唯一路径(例如,对于值“ rootfs”,第一路径:“ system.filesystem.type”,第二路径:“ system.filesystem.device_name”)。 / p>

非常感谢,感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

一种简单的方法是将getpath变成生成器:

def getpath(nested_dict, value, prepath=()):
    for k,v in nested_dict.items():
        path = prepath + (k,)
        if v == value: # found value
            yield path # yield the value
        elif hasattr(v, 'items'):
            yield from getpath(v, value, path) # yield all paths from recursive call

通过这种方式递归yields每个有效路径。您可以像这样使用它:

for path in getpath(nested_dict, value):
    # do stuff with path