通过键列表访问嵌套字典项目?
我有一个复杂的字典结构,我想通过一系列的键来访问正确的项目。
dataDict = { "a":{ "r": 1, "s": 2, "t": 3 }, "b":{ "u": 1, "v": { "x": 1, "y": 2, "z": 3 }, "w": 3 } } maplist = ["a", "r"]
要么
maplist = ["b", "v", "y"]
我做了下面的代码,但我敢肯定有一个更好,更有效的方法来做到这一点,如果任何人有一个想法。
# Get a given data from a dictionary with position provided as a list def getFromDict(dataDict, mapList): for k in mapList: dataDict = dataDict[k] return dataDict # Set a given data in a dictionary with position provided as a list def setInDict(dataDict, mapList, value): for k in mapList[:-1]: dataDict = dataDict[k] dataDict[mapList[-1]] = value
使用reduce()
来遍历字典:
from functools import reduce # forward compatibility for Python 3 import operator def getFromDict(dataDict, mapList): return reduce(operator.getitem, mapList, dataDict)
getFromDict
用getFromDict
来查找存储setInDict()
的值的位置:
def setInDict(dataDict, mapList, value): getFromDict(dataDict, mapList[:-1])[mapList[-1]] = value
除了mapList
的最后一个元素外,还需要找到要添加值的“父”字典,然后使用最后一个元素将值设置为右键。
演示:
>>> getFromDict(dataDict, ["a", "r"]) 1 >>> getFromDict(dataDict, ["b", "v", "y"]) 2 >>> setInDict(dataDict, ["b", "v", "w"], 4) >>> import pprint >>> pprint.pprint(dataDict) {'a': {'r': 1, 's': 2, 't': 3}, 'b': {'u': 1, 'v': {'w': 4, 'x': 1, 'y': 2, 'z': 3}, 'w': 3}}
- 被接受的解决方案不会直接为python3工作 – 它将需要一个
from functools import reduce
。 - 另外,使用
for
循环似乎可能更pythonic。 请参阅Python 3.0中的新功能 。
删除了
reduce()
。 使用functools.reduce()
如果你真的需要它; 但是,显式循环的99%时间更具可读性。 - 接下来,接受的解决方案不会设置不存在的嵌套键(它返回一个KeyError) – 请参阅@ eafit的解答
那么为什么不从kolergy的问题中使用建议的方法来获得价值:
def getFromDict(dataDict, mapList): for k in mapList: dataDict = dataDict[k] return dataDict
而从@ eafit的代码来设置一个值的答案:
def nested_set(dic, keys, value): for key in keys[:-1]: dic = dic.setdefault(key, {}) dic[keys[-1]] = value
这两个工作直接在python 2和3
这个库可能会有所帮助: https : //github.com/akesterson/dpath-python
一个Python库,通过/ slashed /路径ala xpath访问和搜索字典
基本上它可以让你像字典一样遍历字典。
使用reduce是聪明的,但如果父键不在嵌套字典中,则OP的set方法可能会有问题。 由于这是我在谷歌搜索中看到的这个主题的第一个SO帖子,我想稍微改进一下。
( 给定一个索引和值的列表中设置一个嵌套的Python字典中的值 )似乎更强大的丢失父母的关键。 要复制它:
def nested_set(dic, keys, value): for key in keys[:-1]: dic = dic.setdefault(key, {}) dic[keys[-1]] = value
另外,可以方便地使用遍历键树并获取所有绝对键路径的方法,为此我创建了:
def keysInDict(dataDict, parent=[]): if not isinstance(dataDict, dict): return [tuple(parent)] else: return reduce(list.__add__, [keysInDict(v,parent+[k]) for k,v in dataDict.items()], [])
它的一个用途是将嵌套树转换为pandas DataFrame,使用下面的代码(假设嵌套字典中的所有叶子具有相同的深度)。
def dict_to_df(dataDict): ret = [] for k in keysInDict(dataDict): v = np.array( getFromDict(dataDict, k), ) v = pd.DataFrame(v) v.columns = pd.MultiIndex.from_product(list(k) + [v.columns]) ret.append(v) return reduce(pd.DataFrame.join, ret)
每次你想要查找一个值,而不是每次想要获得一个性能,那么你如何平整字典一次,然后简单地查找键如b:v:y
def flatten(mydict): new_dict = {} for key,value in mydict.items(): if type(value) == dict: _dict = {':'.join([key, _key]):_value for _key, _value in flatten(value).items()} new_dict.update(_dict) else: new_dict[key]=value return new_dict dataDict = { "a":{ "r": 1, "s": 2, "t": 3 }, "b":{ "u": 1, "v": { "x": 1, "y": 2, "z": 3 }, "w": 3 } } flat_dict = flatten(dataDict) print flat_dict {'b:w': 3, 'b:u': 1, 'b:v:y': 2, 'b:v:x': 1, 'b:v:z': 3, 'a:r': 1, 'a:s': 2, 'a:t': 3}
这样,你可以简单地使用flat_dict['b:v:y']
来查找项目,这会给你1
。
而不是在每次查找时遍历字典,您可以通过展开字典并保存输出来加快速度,以便从冷启动查找意味着加载扁平字典并简单地执行键/值查找遍历。