Превращаем вложенный словарь в плоский. Неправильный вывод

Рейтинг: 1Ответов: 2Опубликовано: 11.01.2023

Задача

Превращаем вложенный словарь в плоский

Перед вами имеется вложенный словарь, уровень вложенности произвольный и заранее неизвестен. Ключами словаря на любом уровне могут быть только строки, значения - только числа.

Учитывая указанные выше условия, ваша задача состоит в том, чтобы преобразовать этот вложенный словарь в плоский (состоящий только из одного уровня), где ключи формируются конкатенацией вложенных ключей, соединенных знаком: _

Для этого необходимо определить рекурсивную функцию flatten_dict. Она должна принимать вложенный словарь и возвращать плоский

Ниже приведены несколько способов решения вышеуказанной задачи.

nested = {'Germany': {'berlin': 7},
          'Europe': {'italy': {'Rome': 3}},
          'USA': {'washington': 1, 'New York': 4}}

flatten_dict(nested) => {'Germany_berlin': 7,
                         'Europe_italy_Rome': 3,
                         'USA_washington': 1,
                         'USA_New York': 4}
nested = {'Q': {'w': {'E': {'r': {'T': {'y': 123}}}}}}

flatten_dict(nested) => {'Q_w_E_r_T_y': 123}

Мой код

def flatten_dict(user_dict: dict[any, any], total_dict: dict[any, any] = {}, x: [str] = [], y: [int] = []) -> dict:
    for key, value in user_dict.items():
        if type(value) == dict:
            x.append(key)
            flatten_dict(user_dict[key], total_dict, x, y)
        else:
            x.append(key)
            y.append(value)
            if type(value) != dict:
                total_dict['_'.join(x)] = y[0]
                x.clear()
                y.clear()
    return total_dict

Проблема

Код работает, но при наличии более, так скажем, одной цифры в ряду словарей, выводит неправильно. Пример:

ввожу:

flatten_dict({'Germany':7,'Europe': {'italy': {'Rome': 3}},'USA': {'washington': 1, 'New York': 4}}))

выводит:

{'Germany': 7, 'Europe_italy_Rome': 3, 'USA_washington': 1, 'New York': 4}

Ответы

▲ 4Принят
def flatten(nested_dict={}, flatten_dict={}):
    for key, value in nested_dict.items():
        if isinstance(value, dict):
            flatten({f'{key}_{sub_key}': sub_value for sub_key, sub_value in value.items()}, flatten_dict)
        else:
            flatten_dict[key] = value

    return flatten_dict


nested = {'Germany':7,'Europe': {'italy': {'Rome': 3}},'USA': {'washington': 1, 'New York': 4}}

print(flatten(nested))
# {'Germany': 7, 'Europe_italy_Rome': 3, 'USA_washington': 1, 'USA_New York': 4}
▲ 2

Я бы немного модернизировал предыдущий код что бы сделать разные словари при вызове функции так как при запуске нескольких проверок накапливается в один и тот же словарь

def flatten_dict(nested_dict={}, flatten=None):
    if flatten is None:
        flatten = {}
    for key, value in nested_dict.items():
        if isinstance(value, dict):
            flatten_dict({f'{key}_{sub_key}': sub_value for sub_key,
                         sub_value in value.items()}, flatten)
        else:
            flatten[key] = value
    return flatten

assert flatten_dict({'Q': {'w': {'E': {'r': {'T': {'y': 123}}}}}}) == {
    'Q_w_E_r_T_y': 123}
assert flatten_dict({'Germany_berlin': 7,
                     'Europe_italy_Rome': 3,
                     'USA_washington': 1,
                     'USA_New York': 4}) == {'Germany_berlin': 7, 'Europe_italy_Rome': 3, 'USA_washington': 1,
                                             'USA_New York': 4}
assert flatten_dict({'a': 100, 'b': 200}) == {'a': 100, 'b': 200}
assert flatten_dict(
    {'Geeks': {'for': {'for': 1, 'geeks': 4}}, 'for': {'geeks': {'Geeks': 3}}, 'geeks': {'Geeks': {'for': 7}}}) == {
           'Geeks_for_geeks': 4, 'for_geeks_Geeks': 3, 'geeks_Geeks_for': 7, 'Geeks_for_for': 1}
assert flatten_dict({"a": 1,
                     "b": {
                         "c": 2,
                         "d": 3,
                         "e": {
                             "f": 4,
                             '6': 100,
                             '5': {"g": 6},
                             "l": 1,
                         }
                     }}) == {'a': 1, 'b_c': 2, 'b_d': 3, 'b_e_f': 4, 'b_e_6': 100, 'b_e_5_g': 6, 'b_e_l': 1}