Функция от python, которая изменяет тип ключа в словаре

Имеется двух-уровневый словарь со строковыми ключами:

{'3': {'0': [68, 13]}, '4': {'0': [8, 58]}, '2': {'0': [6]}}

Я написал свой обработчик, который преобразует ключи в целочисленные:

def test(dict_in):
    cash_ = {}
    for key, val in dict_in.items():
        key = int(key)
        if isinstance(val, dict):
            cash_[key] = test(val)
        else:
            cash_[key] = val
    return cash_

Итог работы:

{3: {0: [68, 13]}, 4: {0: [8, 58]}, 2: {0: [6]}}

Собственно сам вопрос: есть ли стандартная функция от Python, которая делает тоже самое?


Ответы (4 шт):

Автор решения: strawdog

думаю, что такой специальной функции нет. но для больших данных для двухуровневого словаря можно попробовать повысить эффективность с помощью pandas, например.

import pandas as pd
d = {'3': {'0': [68, 13]}, '4': {'0': [8, 58]}, '2': {'0': [6]}}
df = pd.DataFrame(d)
df.index = df.index.astype(int)
df.columns = df.columns.astype(int)
res = df.to_dict()

res:

{3: {0: [68, 13]}, 4: {0: [8, 58]}, 2: {0: [6]}}

разумеется, здесь не проводится проверка на исключения.

→ Ссылка
Автор решения: Dmitry

Не могу подвергать сомнению решение с pandas, поскольку не компетентен. Но если, вы используете json в вашем API, то его можно сразу при преобразовании в питоновский словарь привести к нужному виду через параметра object_hooks, при вызове метода load (или loads, не имеет значения).

import json

# функция обработки
def parse_keys_to_int(initial_value):
    if isinstance(initial_value, dict):
        return {int(key):value for key,value in initial_value.items()}
    return initial_value

# входные данные
d = {'3': {'0': [68, 13]}, '4': {'0': [8, 58]}, '2': {'0': [6]}}

# симуляция в json формат
f = json.dumps(d)

# обработка json, которые приходит с не верным типом данных ключей
c = json.loads(f, object_hook=parse_keys_to_int)

Результат

{3: {0: [68, 13]}, 4: {0: [8, 58]}, 2: {0: [6]}}

Преимущества:

  1. Все равно, какая вложенность.

    d = {'3': {'0': [68, 13]}, '4': {'0': [8, 58]}, '2': {'0': [6], '2': {'0': [6], '2': {'0': [6]}}}}
    
    # результат будет
    {3: {0: [68, 13]}, 4: {0: [8, 58]}, 2: {0: [6], 2: {0: [6], 2: {0: [6]}}}}
    
  2. Все равно, какая структура json, это может быть список словарей (в терминологии python)

    d = [{'3': {'0': [68, 13]}, '4': {'0': [8, 58]}, '2': {'0': [6], '2': {'0': [6], '2': {'0': [6]}}}}, 
     {'3': {'0': [68, 13]}, '4': {'0': [8, 58]}, '2': {'0': [6], '2': {'0': [6], '2': {'0': [6]}}}},
     {'3': {'0': [68, 13]}, '4': {'0': [8, 58]}, '2': {'0': [6], '2': {'0': [6], '2': {'0': [6]}}}}]
    
    # результат будет
    [{3: {0: [68, 13]}, 4: {0: [8, 58]}, 2: {0: [6], 2: {0: [6], 2: {0: [6]}}}}, {3: {0: [68, 13]}, 4: {0: [8, 58]}, 2: {0: [6], 2: {0: [6], 2: {0: [6]}}}}, {3: {0: [68, 13]}, 4: {0: [8, 58]}, 2: {0: [6], 2: {0: [6], 2: {0: [6]}}}}]
    
  3. Возможность добавить обаботку исключений и поведение для ключей другого типа, просто изменив функцию обработки parse_keys_to_int()

→ Ссылка
Автор решения: CrazyElf

Вариант через рекурсию и словарное включение:

def int_key(d):
    return {int(k):int_key(v) for k, v in d.items()} if isinstance(d, dict) else d

dict_ = {'3': {'0': [68, 13]}, '4': {'0': [8, 58]}, '2': {'0': [6]}}

new_dict = int_key(dict_)
print(new_dict)

# {3: {0: [68, 13]}, 4: {0: [8, 58]}, 2: {0: [6]}}

P.S. Вариант кода для более сложного словаря:

def int_key(d):
    return {int(k) if str.isdigit(k) else k:int_key(v) for k, v in d.items()} if isinstance(d, dict) else d

dict_ = {'5':
 {'1': {'text_key_1': [309], 'text_key_2': 0},
  '0': {'text_key_1': [406], 'text_key_2': 0}},
 '6':
 {'1': {'text_key_1': [311], 'text_key_2': 0},
  '0': {'text_key_1': [446], 'text_key_2': 0}}
}

new_dict = int_key(dict_)
print(new_dict)

Вывод:

{5: {0: {'text_key_1': [406], 'text_key_2': 0},
     1: {'text_key_1': [309], 'text_key_2': 0}},
 6: {0: {'text_key_1': [446], 'text_key_2': 0},
     1: {'text_key_1': [311], 'text_key_2': 0}}}

Возможно, в случае, если проверок нужно много, удобнее и правда делать через try/except.

→ Ссылка
Автор решения: Алексей Белкин

Хоть и ответ мне помог, но потом ни один ответ не смог правильно работать при другом варианте словаря:

{'5':
 {'1': {'text_key_1': [309], 'text_key_2': 0},
  '0': {'text_key_1': [406], 'text_key_2': 0}},
 '6':
 {'1': {'text_key_1': [311], 'text_key_2': 0},
  '0': {'text_key_1': [446], 'text_key_2': 0}}
}

Поэтому, пришлось вернутся к своему варианту, который маленько модернизировал, но зато он работает исправно. Оставлю, если кому понадобится:

def get_int_key(dict_in):
    cash_ = {}
    for key, val in dict_in.items():
        try:
            key = int(key)
        except:
            key = key
        cash_[key] = get_int_key(val) if isinstance(val, dict) else val
    return cash_
→ Ссылка