kol*_*rgy 128 python dictionary list
我有一个复杂的字典结构,我想通过一个键列表访问,以解决正确的项目.
dataDict = {
"a":{
"r": 1,
"s": 2,
"t": 3
},
"b":{
"u": 1,
"v": {
"x": 1,
"y": 2,
"z": 3
},
"w": 3
}
}
maplist = ["a", "r"]
Run Code Online (Sandbox Code Playgroud)
要么
maplist = ["b", "v", "y"]
Run Code Online (Sandbox Code Playgroud)
我已经制作了以下代码,但是我确信如果有人有想法,有更好更有效的方法.
# 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
Run Code Online (Sandbox Code Playgroud)
Mar*_*ers 196
使用reduce()遍历词典:
from functools import reduce # forward compatibility for Python 3
import operator
def getFromDict(dataDict, mapList):
return reduce(operator.getitem, mapList, dataDict)
Run Code Online (Sandbox Code Playgroud)
并重getFromDict用以查找存储值的位置setInDict():
def setInDict(dataDict, mapList, value):
getFromDict(dataDict, mapList[:-1])[mapList[-1]] = value
Run Code Online (Sandbox Code Playgroud)
除了最后一个元素之外的所有元素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}}
Run Code Online (Sandbox Code Playgroud)
请注意,Python PEP8样式指南规定了函数的snake_case名称.以上内容同样适用于列表或字典和列表的混合,因此名称应该是get_by_path()和set_by_path():
from functools import reduce # forward compatibility for Python 3
import operator
def get_by_path(root, items):
"""Access a nested object in root by item sequence."""
return reduce(operator.getitem, items, root)
def set_by_path(root, items, value):
"""Set a value in a nested object in root by item sequence."""
get_by_path(root, items[:-1])[items[-1]] = value
Run Code Online (Sandbox Code Playgroud)
Dom*_*Cat 31
from functools import reduce.for循环似乎更pythonic .请参阅Python 3.0中的新功能.
删除了
reduce().使用,functools.reduce()如果你真的需要它; 但是,99%的时间显式for循环更具可读性.
KeyError) - 请参阅@ eafit的解决方案的答案那么为什么不使用kolergy的问题中建议的方法来获取值:
def getFromDict(dataDict, mapList):
for k in mapList: dataDict = dataDict[k]
return dataDict
Run Code Online (Sandbox Code Playgroud)
以及来自@ eafit设置值的答案的代码:
def nested_set(dic, keys, value):
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
Run Code Online (Sandbox Code Playgroud)
两者都在python 2和3中直接工作
eaf*_*fit 13
使用reduce很聪明,但如果父键在嵌套字典中不存在,则OP的set方法可能会出现问题.由于这是我在谷歌搜索中看到的第一篇SO帖子,我想稍微好一些.
(在给定索引和值列表的情况下,在嵌套python字典中设置值)中的set方法对于丢失的父键似乎更健壮.复制它:
def nested_set(dic, keys, value):
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
Run Code Online (Sandbox Code Playgroud)
此外,有一个方法可以方便地遍历密钥树并获取我创建的所有绝对密钥路径:
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()], [])
Run Code Online (Sandbox Code Playgroud)
它的一个用途是使用以下代码将嵌套树转换为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)
Run Code Online (Sandbox Code Playgroud)
这个库可能会有所帮助:https://github.com/akesterson/dpath-python
一个python库,用于通过/ slashed/paths ala xpath访问和搜索字典
基本上它可以让你在字典上覆盖,就像它是一个文件系统一样.
使用递归函数怎么样?
获取一个值:
def getFromDict(dataDict, maplist):
first, rest = maplist[0], maplist[1:]
if rest:
# if `rest` is not empty, run the function recursively
return getFromDict(dataDict[first], rest)
else:
return dataDict[first]
Run Code Online (Sandbox Code Playgroud)
并设置一个值:
def setInDict(dataDict, maplist, value):
first, rest = maplist[0], maplist[1:]
if rest:
try:
if not isinstance(dataDict[first], dict):
# if the key is not a dict, then make it a dict
dataDict[first] = {}
except KeyError:
# if key doesn't exist, create one
dataDict[first] = {}
setInDict(dataDict[first], rest, value)
else:
dataDict[first] = value
Run Code Online (Sandbox Code Playgroud)