提问人:DevArchitectMaster 提问时间:6/20/2023 最后编辑:DevArchitectMaster 更新时间:6/21/2023 访问量:120
高效的 Python 函数,无需外部库即可获取嵌套字典中特定键的值,也不知道字典中键的具体静态路径
efficient python function to get value of specific key in nested dict without an external lib and without knowing concret static path to key in dict
问:
初始情况如下:
我正在寻找一个自定义函数,该函数将从嵌套字典中提取相应的值,并在没有外部库的情况下返回它,并且不会将整个静态路径弯曲到相应的键。函数“搜索路径”(dict 键)应该类似于 CSS 或 XPATH 选择器,例如
getValue(nestedDict, "[subkey1][subkey42InSubkey1]") # "[subkey1][subkey42InSubkey1]" = "search path"
此函数 () 应在 中搜索键,并在其中搜索键,然后返回值(如果找到)或 None。getValue()
nestedDict
subkey1
subkey42InSubkey1
但是,该函数应该是动态的,嵌套字典的深度无关紧要。 此外,“搜索路径”应该是相对指定的,即不必知道整个嵌套字典的绝对路径。
问题:
你能帮我创建这样的函数吗?
这样的函数是否应该通过递归来解决,以便比循环更有效?
非常感谢您的帮助!
Python 代码
test_dict = {
"a" : "1",
"b" : {
"1" : 2,
"2" : 4711,
"3" : {
"b31" : 31
},
"4" : 4
},
"c" : "3",
"d" : {
"1" : 5,
"2" : 9,
"3" : {
"c31" : 55
}
}
}
test_result = 55
# get value in nested dict like CSS- respectively XPATH Selector
def getValue(nestedDict, key):
#TODO
result = None
return result
####################################################################################
if __name__ == '__main__':
result = getValue(test_dict, "[3][c31]") # should return 55 as a result
# the following call should yield the same result!
result2 = getValue(test_dict, "[d][3][c31]") # should return 55 as a result too
assert result == test_result
print(result)
我有一个“非干净代码”的解决方案,我对自己不满意,所以我避免在这里发布它,以免在无意中回答问题时产生偏见。感谢您的理解!
答:
一种可能的方法:
递归生成器,用于在嵌套字典中的任何位置查找单个键的所有值:
def find(nested_dict, key):
if key in nested_dict:
yield nested_dict[key]
for v in nested_dict.values():
if isinstance(v, dict):
yield from find(v, key)
find(test_dict, "3")
# {"b31" : 31}
# {"c31" : 55}
帮助程序访问字典中键的具体路径:
def access(obj, bits):
for bit in bits:
obj = obj[bit] # this can cause errors: obj not a dict or key missing
return obj
access(test_dict, ["d", "3", "c31"])
# 55
access(test_dict, ["b", "4"])
# 4
最终值收集:
def get_values(nested_dict, search_path): # e.g. search_path "[d][3][c31]"
start, *tail = search_path.strip("[]").split("][")
# start: "d"
# tail: ["3", "c31"]
for d in find(nested_dict, start): # e.g. all occurrences of "d"
try:
yield access(d, tail) # then access e.g. ["3", "c31"] inside of them
except (KeyError, TypeError):
pass # key missing, d or any value down the path not a dict
>>> list(get_values(test_dict, "[d][3][c31]"))
[55]
>>> list(get_values(test_dict, "[3][c31]"))
[55]
>>> list(get_values(test_dict, "[c31]"))
[55]
>>> list(get_values(test_dict, "[2]"))
[4711, 9]
>>> list(get_values(test_dict, "[b][2]"))
[4711]
这将返回一个列表,因为可能有 1 个以上的匹配项。它可以很容易地修改为通过在函数中更改为仅返回第一个。yield
return
get_values
评论
list(get_values(test_dict, "[d][3][c31]")) -> [55]
如果您将“”添加到类似 XPATH 的选择器中,这将起作用。我想你应该这样做,因为字典键不是必需的字符串。
def get_value(nested_dict, key):
res = None
try:
res = eval("nested_dict" + key)
except KeyError:
for v in nested_dict.values():
if isinstance(v, dict):
res = get_value(v, key)
return res
get_value(test_dict, "['3']['c31']")
在示例中返回“55”。
请注意,如果您当时无法完全控制您的数据,那么使用是一个坏主意。eval
评论
getValue(test_dicct, "[d][3][c31]")