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

Bas*_*aar 25 python dictionary replace nested character

我正在尝试创建一个泛型函数来替换嵌套字典的键中的点.我有一个非泛型函数,深入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)
Run Code Online (Sandbox Code Playgroud)

更新:回答我自己的问题,我使用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
Run Code Online (Sandbox Code Playgroud)

hor*_*sek 29

是的,有更好的方法:

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
Run Code Online (Sandbox Code Playgroud)

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

  • 此解决方案仅在所有值均为dicts时有效.如果值是一个dicts列表,它将失败 - 将无法达到列表中的dicts. (7认同)
  • @bk0 它创建新字典。初始键不在返回的新字典中。 (2认同)
  • @aryeh 是的,这也是一个问题。无法为所有事情编写通用解决方案。:-) (2认同)

jll*_*ino 6

我使用了@horejsek的代码,但我修改了它以接受带有列表的嵌套字典和替换字符串的函数.

我有一个类似的问题要解决:我想用下划线小写约定替换驼峰大小写约定的键,反之亦然.

def change_dict_naming_convention(d, convert_function):
    """
    Convert a nested dictionary from one convention to another.
    Args:
        d (dict): dictionary (nested or not) to be converted.
        convert_function (func): function that takes the string in one convention and returns it in the other one.
    Returns:
        Dictionary with the new keys.
    """
    new = {}
    for k, v in d.iteritems():
        new_v = v
        if isinstance(v, dict):
            new_v = change_dict_naming_convention(v, convert_function)
        elif isinstance(v, list):
            new_v = list()
            for x in v:
                new_v.append(change_dict_naming_convention(x, convert_function))
        new[convert_function(k)] = new_v
    return new
Run Code Online (Sandbox Code Playgroud)


小智 6

这是一个处理嵌套列表和字典的简单递归解决方案。

def change_keys(obj, convert):
    """
    Recursivly goes through the dictionnary obj and replaces keys with the convert function.
    """
    if isinstance(obj, dict):
        new = {}
        for k, v in obj.iteritems():
            new[convert(k)] = change_keys(v, convert)
    elif isinstance(obj, list):
        new = []
        for v in obj:
            new.append(change_keys(v, convert))
    else:
        return obj
    return new
Run Code Online (Sandbox Code Playgroud)


bal*_*ldr 6

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

我会用@ngenain的答案,并在下面进行一些改进。

我的解决方案将采取关心源自类型dictOrderedDictdefaultdict,等),也即将不仅list,而且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
Run Code Online (Sandbox Code Playgroud)

如果我理解正确的需求,那么大多数用户都希望将密钥转换为可在mongoDB中使用,而mongoDB不允许密钥名称中包含点。

  • 很好的答案。为了完整起见,我将为您的答案添加转换函数:`def Convert(k): return k.replace('.', '-')` (3认同)