如何在任意深度

时间:2017-05-29 14:52:40

标签: python dictionary recursion

我有一个字典,其中包含字典,而字典可能会无限地包含字典。我想更改所有字典中的每个键,但映射到其中一个嵌套字典的键除外。我知道密钥是不可变的,我想做的事情是这样的:

layer[item + '_addition'] = layer.pop(item)

我现在拥有的是:

def alterKeys(item, layer=topLevelDict):
    if isinstance(item, dict):
        for i in item:
            alterKeys(item[i], item)
    else:
        layer[item + '_addition'] = layer.pop(item)

这不起作用,因为它会不断地递归到树中,直到最后一行尝试从dict中弹出一个值,而不是一个键,这会引发一个KeyError。 我知道我已经接近解决方案,但我已经考虑了几分钟而且我似乎无法弄明白。

3 个答案:

答案 0 :(得分:1)

在写这个问题时,我想出来了。我想我会发布这个以防其他人在某些时候有同样的问题。

def alterKeys(item, layer=topLevelDict, key=None):
    if isinstance(item, dict):
        for k, v in item.items():
            alterKeys(v, item, k)
    elif isinstance(key, str):
        layer[key + '_addition'] = layer.pop(key)

如果有人有更优雅或更好的解决方案,我很乐意看到它。我刚刚通过它运行一个json文件测试了这个脚本,它重命名了没有映射到字典的每个键,这正是我想要的。

如果我希望重命名每个键,包括那些映射到嵌套词典的键,我可以使用这个代码:

def alterKeys(item, layer=topLevelDict, key=None):
    if isinstance(item, dict):
        for k, v in item.items():
            alterKeys(v, item, k)
    if isinstance(key, str):
        layer[key + '_addition'] = layer.pop(key)

如果您使用的是python2,请记住使用.iteritems()而不是.items(),并使用isinstance(key,basestring)而不是isinstance(key,str)。

答案 1 :(得分:0)

我在寻找一个解决方案时遇到了这个问题,所以我想我会发布自己的python 3.7.4解决方案。

以下代码将迭代对象,该对象是有序dict和list的嵌套组合,并且以下代码会将名为@index的所有字段重命名为id

from collections import OrderedDict

def rename_index_to_id(iterable):
    if type(iterable) is OrderedDict:
        for key in list(iterable.keys()):
            if key == "@index":
                iterable["id"] = iterable["@index"]
                del iterable[key]
        for obj in iterable:
            rename_index_to_id(iterable[obj])
    elif type(iterable) is list:
        for obj in iterable:
            rename_index_to_id(obj)

答案 2 :(得分:0)

我修改了@solution 中的 martin-riddar 以使其更通用。

from collections import OrderedDict
def rename_dict_key(the_dict, old_key_name, new_key_name):
  if type(the_dict) in [dict, OrderedDict]:
    for key in list(the_dict.keys()):
      if key == old_key_name:
        the_dict[new_key_name] = the_dict[old_key_name]
        del the_dict[key]
    for obj in the_dict:
      rename_dict_key(the_dict[obj], old_key_name, new_key_name)
  elif type(the_dict) is list:
    for obj in the_dict:
      rename_dict_key(obj, old_key_name, new_key_name)

注意:我使用 dict 而不是 OrderedDict 对此进行了测试,但我认为结果不会有任何不同。