Подтвердить что ты не робот

Рекурсивно заменить символы в словаре

Как изменить все точки . на подчеркивания (в клавишах dict), с учетом произвольного вложенного словаря?

Я попытался написать два цикла, но тогда я бы ограничился 2-уровневыми вложенными словарями.

Это...

{
    "brown.muffins": 5,
    "green.pear": 4,
    "delicious.apples": {
        "green.apples": 2
    {
}

... должен стать:

{
    "brown_muffins": 5,
    "green_pear": 4,
    "delicious_apples": {
        "green_apples": 2
    {
}

Есть ли элегантный способ?

4b9b3361

Ответ 1

Вы можете написать рекурсивную функцию, например

from collections.abc import Mapping
def rec_key_replace(obj):
    if isinstance(obj, Mapping):
        return {key.replace('.', '_'): rec_key_replace(val) for key, val in obj.items()}
    return obj

и когда вы вызываете это со словарем, который вы указали в вопросе, вы получите новый словарь, в котором точки в ключах заменены на _ s

{'delicious_apples': {'green_apples': 2}, 'green_pear': 4, 'brown_muffins': 5}

Объяснение

Здесь мы просто проверяем, является ли текущий объект экземпляром dict, и если это так, мы перебираем словарь, заменяем ключ и вызываем функцию рекурсивно. Если на самом деле это не словарь, верните его как есть.

Ответ 2

Предполагая, что . присутствует только в ключах, и все содержимое словаря являются примитивными литералами, очень дешевым способом было бы использовать str() или repr(), выполнить замену, а затем ast.literal_eval(), чтобы вернуть его:

d ={
    "brown.muffins": 5,
    "green.pear": 4,
    "delicious_apples": {
        "green.apples": 2
    } # correct brace
}

Результат:

>>> import ast
>>> ast.literal_eval(repr(d).replace('.','_'))
{'delicious_apples': {'green_apples': 2}, 'green_pear': 4, 'brown_muffins': 5}

Если словарь имеет . вне ключей, мы можем более осторожно заменить его, используя регулярное выражение для поиска строк типа 'ke.y': и заменим только те биты:

>>> import re
>>> ast.literal_eval(re.sub(r"'(.*?)':", lambda x: x.group(0).replace('.','_'), repr(d)))
{'delicious_apples': {'green_apples': 2}, 'green_pear': 4, 'brown_muffins': 5}

Если ваш словарь очень сложный, с '.' в значениях и словарными строками и т.д., используйте реальный рекурсивный подход. Как я уже сказал в начале, это дешевый способ.