如何在嵌套词典的键中递归替换字符? 我正在尝试创建一个通用函数,该函数替换嵌套词典的键中的点。我有一个非传播功能,可以深入3个级别,但是必须有一种方法来执行此通用。任何HEL ...

问题描述 投票:0回答:7

update:要回答我自己的问题,我使用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

是的,存在更好的方法:

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
python dictionary replace nested character
7个回答
45
投票
。)

实际上,所有答案都包含一个错误,该错误可能导致在结果中键入错误。

我会得到@ngenain的答案,并在下方进行一些改进。 我的解决方案将注意从dict

OrderedDict

22
投票
defaultdict

等)中得出的类型,也将不仅大约

list

,而且type。

我还在功能开头的最常见类型进行简单类型检查,以减少比较计数(可能会在大量数据中给出一些速度)。

为Python 3。替换为py2的工作。

set
如果我了解正确的需求,大多数用户都希望将其与mongoDB一起使用的密钥转换为不允许以关键名称的点。
    
i我使用@HoreJsek的代码,但是我对其进行了调整以接受列表的嵌套字典和替换字符串的函数。

我也有类似的问题要解决:我想在骆驼案例中限制下的小写惯例中替换键,反之亦然。 
tuple
    
there是一个简单的递归解决方案,涉及嵌套列表和字典。

obj.items()

您必须删除原始键,但是您不能在循环的主体中进行操作,因为它会抛出RuntimeRoror:字典在迭代过程中更改了大小。

要解决此问题,通过原始对象的
a复制
进行迭代,但要修改原始对象:

obj.iteritems()


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


8
投票

你可以将所有东西都丢给json 通过整个字符串替换并加载JSON背面

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

或使用单线

7
投票

虽然jlopezpino的答案有效,但仅限于词典的开始,这是我的原始变量既要么列表或dict oct。

def change_keys(obj): new_obj = obj for k in new_obj: if hasattr(obj[k], '__getitem__'): change_keys(obj[k]) if '.' in k: obj[k.replace('.', '$')] = obj[k] del obj[k]

2
投票

there是@Horejsek的回答的1级变体,使用dict理解者对那些喜欢的人:

>>> foo = {'foo': {'bar': {'baz.121': 1}}} >>> change_keys(foo) >>> foo {'foo': {'bar': {'baz$121': 1}}} 我只在Python2.7

中测试了这一点

我猜想您遇到的问题与我相同,将词典插入蒙古多德(Mongodb)集合中,在尝试插入带有点(。)键的字典时遇到异常。

该解决方案本质上与这里的大多数其他答案基本相同,但是它更紧凑,并且可能不那么可读性,因为它使用单个语句并递归地调用自己。对于Python3.
def nested_replace(data, old, new):
    json_string = json.dumps(data)
    replaced = json_string.replace(old, new)
    fixed_json = json.loads(replaced)
    return fixed_json

1
投票

动物的方法/解决方案用于更改键:
def short_replace(data, old, new):
    return json.loads(json.dumps(data).replace(old, new))

输出:
def fix_camel_cases(data):
    def convert(name):
        # https://stackoverflow.com/questions/1175208/elegant-python-function-to-convert-camelcase-to-snake-case
        s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
        return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()

    if isinstance(data, dict):
        new_dict = {}
        for key, value in data.items():
            value = fix_camel_cases(value)
            snake_key = convert(key)
            new_dict[snake_key] = value
        return new_dict

    if isinstance(data, list):
        new_list = []
        for value in data:
            new_list.append(fix_camel_cases(value))
        return new_list

    return data

0
投票

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.