V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
L00kback
V2EX  ›  问与答

Python 求问多层嵌套字典怎么改值,套娃字典真是大坑

  •  
  •   L00kback · 2020-10-15 17:43:12 +08:00 · 2878 次点击
    这是一个创建于 1501 天前的主题,其中的信息可能已经有所发展或是发生改变。

    事情是这样的,有一个字典嵌套列表,列表嵌套字典,然后字典又嵌套了列表。列表里面的元素结构都是一样的:

    example={'a': 
            	{'b': 
                	[{'c': [{'d': 11}, {'d': 12}]},
                 	 {'c': [{'d': 21}, {'d': 22}, {'d': 23}]},
                     {'c': [{'d': 21}, {'d': 22}, {'d': 23}]}
                	]
            	}
         	}
    

    需要更新 d 的值(比如都+1),有没有办法给出一个路由input=[a,b,c,d]直接定位到 d 然后改它的值?目前只想到这种方法比较方便,有别的方法请指导!

    直接绝对路径去改量贼大很麻烦,有些 key 都不止套一层。数据发过来是这样的没有办法改。

    提前感谢各位大佬了

    第 1 条附言  ·  2020-10-26 09:34:06 +08:00

    自己update一下

    • 需求:更新嵌套字典中的指定key的值,原来的值=plus_one(原来的值)
    • 数据特点:key值都是唯一的且数据类型一致

    最终选择了用递归搜索key值来更改。因为发现用btree的话最后还要转回去,效率很低。代码如下;

    def function(key,data):
        for items in data: 
            # 如果子元素的类型是dict,调用自己,传入key值和子元素
            if isinstance(data[items],dict):  
                function(key,data[items])
            # 如果子元素类型是list,遍历子元素的每个子元素(孙子元素?),调用自己并把孙子元素作为data传入
            elif isinstance(data[items],list):  
                for i in range(len(data[items])):
                    function(key,data[items][i])
            # 如果key值符合,调用plus_one函数,并返回data
            elif items == key:  
                try:
                    data[items]=plus_one(data[items])
                    return data
                except:
                    pass
            else:
                pass
        return data     # 返回data
    
    6 条回复    2020-10-19 15:58:32 +08:00
    Yourshell
        1
    Yourshell  
       2020-10-15 17:57:08 +08:00
    遍历
    black11black
        2
    black11black  
       2020-10-16 06:55:10 +08:00 via Android
    简单想了一下应该是除了笨方法以外没什么好办法,只要你现在还在用这种数据结构的话。根据需求可以改结构,比如改成写入友好的,增加读取开销
    L00kback
        3
    L00kback  
    OP
       2020-10-16 09:23:22 +08:00
    @black11black 非常感谢,确实是这种存储方式不利于更改,只能想办法换数据结构了
    Magic347
        4
    Magic347  
       2020-10-16 18:48:02 +08:00
    可以把字典这种数据结构看成是一棵树,字典里的每个(key, val) pair 就是这棵树上的一个节点,
    这个问题的复杂之处在于这里的 val 值类型可能是基础数据类型(比如数值、字符串或布尔),也可能是字典类型或者列表类型,如果一旦是字典类型或者列表类型,那么我们还需要进一步去查看这个 val 内部是否有我们需要寻找的 key 。

    所以其实这个问题就转化为,想办法扫描一遍这棵树所有的节点找到指定的 key,然后更新对应的 val 即可,其实也就归结为一个树的遍历问题,这里使用实现上更方便的 dfs 方式(深度优先遍历,可以递归实现),代码如下,希望对你有所启发:

    def _update(val):
       return val + 1 #TODO

    def modify(dic):
       for key, val in dic.items():
          if key == "d" and type(val) == type(1):
             dic[key] = _update(val)
          elif type(val) == type({}):
             modify(val) # recursively call function
          elif type(val) == type([]):
             if len(val) > 0:
                for _dic in val:
                   modify(_dic) # recursively call function
    L00kback
        5
    L00kback  
    OP
       2020-10-19 15:03:53 +08:00
    @Magic347
    感谢老哥!!!太感动了
    建了一个 BTree,成功了!谢谢🙏
    现在是用一个数组存节点,节点保存值、下一跳、下一跳的 key 值(字典用字典的 key,数组用位置标号)
    搜索和更新还是遍历所有节点的方式做的,递归有时间再看了哈哈
    Magic347
        6
    Magic347  
       2020-10-19 15:58:32 +08:00
    @L00kback 赞~不客气,哈哈
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2126 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 00:02 · PVG 08:02 · LAX 16:02 · JFK 19:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.