如何递归替换嵌套字典键中的字符?

新手上路,请多包涵

我正在尝试创建一个通用函数来替换嵌套字典键中的点。我有一个深入 3 层的非泛型函数,但必须有一种方法来实现这个泛型。任何帮助表示赞赏!到目前为止我的代码:

 output = {'key1': {'key2': 'value2', 'key3': {'key4 with a .': 'value4', 'key5 with a .': 'value5'}}}

def print_dict(d):
    new = {}
    for key,value in d.items():
        new[key.replace(".", "-")] = {}
        if isinstance(value, dict):
            for key2, value2 in value.items():
                new[key][key2] = {}
                if isinstance(value2, dict):
                    for key3, value3 in value2.items():
                        new[key][key2][key3.replace(".", "-")] = value3
                else:
                    new[key][key2.replace(".", "-")] = value2
        else:
            new[key] = value
    return new

print print_dict(output)

更新:为了回答我自己的问题,我使用 json object_hooks 做了一个解决方案:

 import json

def remove_dots(obj):
    for key in obj.keys():
        new_key = key.replace(".","-")
        if new_key != key:
            obj[new_key] = obj[key]
            del obj[key]
    return obj

output = {'key1': {'key2': 'value2', 'key3': {'key4 with a .': 'value4', 'key5 with a .': 'value5'}}}
new_json = json.loads(json.dumps(output), object_hook=remove_dots)

print new_json

原文由 Bas Tichelaar 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 742
2 个回答

是的,有更好的方法:

 def print_dict(d):
    new = {}
    for k, v in d.iteritems():
        if isinstance(v, dict):
            v = print_dict(v)
        new[k.replace('.', '-')] = v
    return new

(编辑:这是递归,更多关于 维基百科。)

原文由 horejsek 发布,翻译遵循 CC BY-SA 3.0 许可协议

实际上所有的答案都包含一个错误,可能会导致输入错误的结果。

我会接受@ngenain 的回答并在下面对其进行一些改进。

My solution will take care about the types derived from dict ( OrderedDict , defaultdict , etc) and also about not only list , but settuple 类型。

我还在函数的开头对最常见的类型进行了简单的类型检查,以减少比较次数(可能会在大量数据中提供一点速度)。

适用于 Python 3。将 obj.items() 替换为 obj.iteritems() 用于 Py2。

 def change_keys(obj, convert):
    """
    Recursively goes through the dictionary obj and replaces keys with the convert function.
    """
    if isinstance(obj, (str, int, float)):
        return obj
    if isinstance(obj, dict):
        new = obj.__class__()
        for k, v in obj.items():
            new[convert(k)] = change_keys(v, convert)
    elif isinstance(obj, (list, set, tuple)):
        new = obj.__class__(change_keys(v, convert) for v in obj)
    else:
        return obj
    return new

如果我对需求的理解是正确的,那么大多数用户都希望将键转换为将它们与不允许键名中包含点的 mongoDB 一起使用。

原文由 baldr 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题