繁体   English   中英

字典:如何列出包含某个值的每个键路径?

[英]Dictionary: How to list every key path that contains a certain value?

假设我有一个形式的嵌套字典:

{'geo': {'bgcolor': 'white','lakecolor': 'white','caxis': {'gridcolor': 'white', 'linecolor': 'white',}},
 'title': {'x': 0.05},
 'yaxis': {'automargin': True,'linecolor': 'white','zerolinecolor': 'white','zerolinewidth': 2}
 }

您如何通过该 dict 工作并列出每个包含值'white'的完整键路径? 使用用户 jfs 定义的 function 在嵌套字典中搜索值 python可以让您检查'white'是否至少出现一次并返回路径:

# dictionary
    d={'geo': {'bgcolor': 'white','lakecolor': 'white','caxis': {'gridcolor': 'white', 'linecolor': 'white',}},
    'title': {'x': 0.05},
    'yaxis': {'automargin': True,'linecolor': 'white','ticks': '','zerolinecolor': 'white','zerolinewidth': 2}
  }

# function:
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
getpath(d,'white')

# out:
('geo', 'bgcolor')

但是“白色”也出现在其他地方,例如:

1. d['geo']['lakecolor']

2: d['geo']['caxis']['gridcolor']

3: d['yaxis']['linecolor']

如何确保 function 找到所有路径?

我已经尝试应用上面的 function 直到它没有返回none内容,同时一个一个地消除找到的路径,但这很快就变成了一个丑陋的混乱。

感谢您的任何建议

这是编写生成器的完美用例:

def find_paths(haystack, needle):
    if haystack == needle:
        yield ()
    if not isinstance(haystack, dict):
        return
    for key, val in haystack.items():
        for subpath in find_paths(val, needle):
            yield (key, *subpath)

您可以按如下方式使用它:

d = {
    'geo': {'bgcolor': 'white','lakecolor': 'white','caxis': {'gridcolor': 'white', 'linecolor': 'white',}},
    'title': {'x': 0.05},
    'yaxis': {'automargin': True,'linecolor': 'white','ticks': '','zerolinecolor': 'white','zerolinewidth': 2}
}

# you can iterate over the paths directly...
for path in find_paths(d, 'white'):
    print('found at path: ', path)

# ...or you can collect them into a list:
paths = list(find_paths(d, 'white'))
print('found at paths: ' + repr(paths))

生成器方法的优点是不需要创建一个对象来一次将所有路径保存在内存中; 它们可以一一处理并立即丢弃。 在这种情况下,内存节省会相当适中,但在其他情况下,它们可能很重要。 此外,如果迭代生成器的循环提前终止,生成器将不会继续搜索更多路径,这些路径无论如何都会被丢弃。

只需转换您的函数,使其返回一个list并且在找到某些内容时不return 只需添加到/扩展列表

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

使用您的输入数据,这会产生(顺序可能因字典无序的python版本而异):

[('yaxis', 'linecolor'), ('yaxis', 'zerolinecolor'), ('geo', 'lakecolor'), 
('geo', 'caxis', 'linecolor'), ('geo', 'caxis', 'gridcolor'), ('geo', 'bgcolor')]

返回是使结果不完整的原因。 不要返回,而是使用单独的列表来跟踪您的路径。 我在这里使用 list cur_list ,并在循环的最后返回它:

d = {
  'geo': {'bgcolor': 'white',
         'caxis': {'gridcolor': 'white', 'linecolor': 'white'},
         'lakecolor': 'white'},
  'title': {'x': 0.05},
  'yaxis': {'automargin': True,
           'linecolor': 'white',
           'ticks': '',
           'zerolinecolor': 'white',
           'zerolinewidth': 2}
}

cur_list = []

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

getpath(d,'white')
print(cur_list)


# RESULT:
# [('geo', 'bgcolor'), ('geo', 'caxis', 'gridcolor'), ('geo', 'caxis', 'linecolor'), ('geo', 'lakecolor'), ('yaxis', 'linecolor'), ('yaxis', 'zerolinecolor')]

我需要这个功能来使用h5py遍历 HDF 文件。 此代码是对 user114332 答案的轻微改动,它查找键而不是值,并在结果中另外产生针,以防它对其他人有用。

import h5py
def find_paths(haystack, needle):
    if not isinstance(haystack, h5py.Group) and not isinstance(haystack, dict):
        return
    
    if needle in haystack:
        yield (needle,)
    
    for key, val in haystack.items():
        for subpath in find_paths(val, needle):
            yield (key, *subpath)

执行:

sf = h5py.File("file.h5py", mode = "w")
g = sf.create_group("my group")
h = g.create_group("my2")
k = sf.create_group("two group")
l = k.create_group("my2")
a = l.create_group("my2")

for path in find_paths(sf, "my2"):
    print('found at path: ', path)

打印以下内容

found at path:  ('my group', 'my2')
found at path:  ('two group', 'my2')
found at path:  ('two group', 'my2', 'my2')

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM