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

时间:2019-12-02 20:54:11

标签: python dictionary

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

    predicted_df = modelo_assessor.predict(to_predict_h2o_frame).as_data_frame()
    predicted_df['PROB_PREDICTED']=predicted_df.iloc[:,1:].max(axis=1)

如何处理该字典,并列出包含值{'geo': {'bgcolor': 'white','lakecolor': 'white','caxis': {'gridcolor': 'white', 'linecolor': 'white',}}, 'title': {'x': 0.05}, 'yaxis': {'automargin': True,'linecolor': 'white','zerolinecolor': 'white','zerolinewidth': 2} } 的每个完整密钥路径? 使用帖子Search for a value in a nested dictionary python中用户jfs定义的函数,可以检查'white'是否至少发生了一次并返回了路径:

'white'

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

1。 # 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')

2 d['geo']['lakecolor']

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

如何确保该功能找到所有路径?

我尝试将上面的函数应用到返回d['yaxis']['linecolor']的位置,同时逐个消除找到的路径,但这很快就变成了一个丑陋的混乱局面。

谢谢您的任何建议!

3 个答案:

答案 0 :(得分:5)

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

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))

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

答案 1 :(得分:1)

只需变换您的函数,使其在发现某些内容时返回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')]

答案 2 :(得分:0)

返回是导致结果不完整的原因。不用返回,而是使用单独的列表来跟踪您的路径。我在这里使用列表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')]
相关问题