Как заменить цифры 2 на 3 в ключах словаря Python, сохранив значения и структуру
Что проверяют
Знаете ли вы, что ключ словаря нельзя переименовать, можно только построить новый словарь. Слова «сохранив структуру» здесь главные: интервьюер ждёт вопросов про тип ключей, вложенность и коллизии. Следом обычно дают словарь, где после замены два ключа совпадают.
Как отвечать
Сначала уточните условия, потом код. Основа это словарный генератор: он не мутирует исходник и сохраняет порядок вставки, который с Python 3.7 гарантирован языком.
def fix_key(k):
if isinstance(k, bool):
return k
if isinstance(k, int):
return int(str(k).replace("2", "3"))
if isinstance(k, str):
return k.replace("2", "3")
return k
def convert(obj):
if isinstance(obj, dict):
return {fix_key(k): convert(v) for k, v in obj.items()}
if isinstance(obj, list):
return [convert(x) for x in obj]
return objЧто стоит проговорить:
- тип ключа:
intостаётсяint, иначе22станет строкой"33"иd[33]перестанет работать.boolпроверяется раньше, потому что это подклассint, иint("True")упадёт; - вложенность: рекурсия проходит по значениям-словарям и спискам, сами значения не меняются;
- коллизии:
{2: "a", 3: "b"}после замены даёт два ключа3, и генератор молча оставит последний. Спросите, что нужно: ошибка, слияние или приоритет; - прочие типы: кортежи и
floatфункция возвращает как есть. Трогать ли2.5, решайте вместе с интервьюером, а не молча; - несколько правил: удобнее
str.translateс таблицей изstr.maketrans.
Исходный словарь остаётся нетронутым, и на него могут ссылаться другие части кода. Проверку покажите одной строкой: convert({2: {22: [{12: 1}]}}) == {3: {33: [{13: 1}]}}.
Где спотыкаются
Меняют словарь во время обхода: d[new] = d.pop(k) внутри for k in d падает с RuntimeError: dictionary changed size during iteration.
Обходят list(d) и меняют на месте. Ошибки нет, но новый ключ 3 затирает ещё не обработанный старый 3.
Приводят все ключи к строкам. Пример из задания проходит, а вызывающий код, который обращается по int, ломается.