首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >通过键列表访问嵌套的字典项?

通过键列表访问嵌套的字典项?
EN

Stack Overflow用户
提问于 2013-02-05 02:04:35
回答 13查看 143.9K关注 0票数 169

我有一个复杂的字典结构,我想通过一个关键字列表来访问它,以找到正确的条目。

代码语言:javascript
复制
dataDict = {
    "a":{
        "r": 1,
        "s": 2,
        "t": 3
        },
    "b":{
        "u": 1,
        "v": {
            "x": 1,
            "y": 2,
            "z": 3
        },
        "w": 3
        }
}    

maplist = ["a", "r"]

代码语言:javascript
复制
maplist = ["b", "v", "y"]

我已经做了下面的代码,可以工作,但我相信有一个更好,更有效的方法来做到这一点,如果谁有一个想法。

代码语言:javascript
复制
# 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
EN

回答 13

Stack Overflow用户

回答已采纳

发布于 2013-02-05 02:07:38

使用reduce()遍历字典:

代码语言:javascript
复制
from functools import reduce  # forward compatibility for Python 3
import operator

def getFromDict(dataDict, mapList):
    return reduce(operator.getitem, mapList, dataDict)

并重用getFromDict来查找存储setInDict()的值的位置

代码语言:javascript
复制
def setInDict(dataDict, mapList, value):
    getFromDict(dataDict, mapList[:-1])[mapList[-1]] = value

mapList中除了最后一个元素之外的所有元素都需要找到要向其添加值的“父”字典,然后使用最后一个元素将值设置为正确的键。

演示:

代码语言:javascript
复制
>>> 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}}

请注意,Python PEP8样式指南prescribes snake_case names for functions。上面的方法同样适用于列表或字典和列表的混合,因此名称实际上应该是get_by_path()set_by_path()

代码语言:javascript
复制
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

为了完整起见,我们使用一个删除键的函数:

代码语言:javascript
复制
def del_by_path(root, items):
    """Delete a key-value in a nested object in root by item sequence."""
    del get_by_path(root, items[:-1])[items[-1]]
票数 287
EN

Stack Overflow用户

发布于 2016-04-29 12:38:54

使用reduce很聪明,但是如果父键没有预先存在于嵌套字典中,那么OP的set方法可能会出现问题。由于这是我在谷歌搜索中看到的第一篇关于这个主题的帖子,我想把它做得稍微好一点。

( Setting a value in a nested python dictionary given a list of indices and value )中的set方法对于丢失的父密钥似乎更健壮。要复制它,请执行以下操作:

代码语言:javascript
复制
def nested_set(dic, keys, value):
    for key in keys[:-1]:
        dic = dic.setdefault(key, {})
    dic[keys[-1]] = value

此外,使用一个遍历密钥树并获取所有绝对密钥路径的方法也很方便,我已经为这些路径创建了以下内容:

代码语言:javascript
复制
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 (假设嵌套字典中的所有leafs都具有相同的深度)。

代码语言:javascript
复制
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)
票数 16
EN

Stack Overflow用户

发布于 2017-03-01 10:07:58

与其每次查找一个值都会影响性能,不如将字典展平一次,然后简单地查找关键字,如b:v:y

代码语言:javascript
复制
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

而不是在每次查找时遍历字典,您可以通过扁平化字典并保存输出来加速这一过程,以便从冷启动的查找将意味着加载扁平化的字典,并简单地执行键/值查找而不遍历。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14692690

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档