Итерация в словаре с неизвестными ключами и неизвестным количеством вложенных словарей [** решено **] - PullRequest
0 голосов
/ 07 ноября 2019

Есть ли лучший способ синтаксического анализа ответов API, при котором я не знаю, сколько вложенных диктов я могу получить?

Изменение ответов API теперь вызывает вложенные дикты. Весь код для получения ответов основан на дикте.

Я нашел ужасный способ, но иногда я получаю вложенные словари 5-го уровня .....

Пример примера ответа:

                    "MalwareProtectionStatus": "disabled",
                    "malware": {
                        "QuarantineStatus": "Disabled",
                        "config": {
                            "av": {
                                "status": "Disabled",
                                "quarantine": {
                                    "status": "Disabled"
                                }
                            },
                            "mg": {
                                "status": "Disabled",
                                "quarantine": {
                                    "status": "Disabled"
                                }
                            }
                        }
                    }

Я подготовил код с входными данными, подобными реальной структуре. Но это ужасный способ сделать это, и если ответ API получает больше уровней вложенных диктов .... тогда ... нужен более ужасный код, посмотрите ....

Мой ужасный код(отредактировано для лучшего понимания):

def flatted(_key, _value):
    flatted_rslt = {}
    for k, v in _value.items():
        flatted_rslt.update({f'{_key}_{k}': v})
    return flatted_rslt


def parse_to_flat(_api_response):
    result = {}
    for key, value in _api_response.items():
        if isinstance(value, dict):
            result.update(flatted(key, value))
        else:
            result.update({key: value})
    return result


if __name__ == '__main__':

    api_response = {'level-a1': '1', 'level-a2': {'level-b1': '21',
                    'level-b2': {'level-c1': '31', 'level-c2': {'level-d1': '41'}}}}

    # flattening level 1
    parsed_api_response_level_1 = parse_to_flat(api_response)
    print(parsed_api_response_level_1)

    # flattening level 2
    parsed_api_response_level_2 = parse_to_flat(parsed_api_response_level_1)
    print(parsed_api_response_level_2)

    # flattening level 3
    parsed_api_response_level_3 = parse_to_flat(parsed_api_response_level_2)
    print(parsed_api_response_level_3)

Код выдает:

{'level-a1': '1', 'level-a2_level-b1': '21', 'level-a2_level-b2': {'level-c1': '31', 'level-c2': {'level-d1': '41'}}}
{'level-a1': '1', 'level-a2_level-b1': '21', 'level-a2_level-b2_level-c1': '31', 'level-a2_level-b2_level-c2': {'level-d1': '41'}}
{'level-a1': '1', 'level-a2_level-b1': '21', 'level-a2_level-b2_level-c1': '31', 'level-a2_level-b2_level-c2_level-d1': '41'}

Это работает ... но только если я знаю уровень вложенных диктов, иногда я вижу 5 уровней...

Любая идея сделать это лучше ????

1 Ответ

0 голосов
/ 12 ноября 2019

Найден лучший вид здесь: Свести вложенные словари, сжимая ключи

def flatten_dict(dd, separator='_', prefix=''):
    return {prefix + separator + k if prefix else k: v
             for kk, vv in dd.items()
             for k, v in flatten_dict(vv, separator, kk).items()
             } if isinstance(dd, dict) else { prefix : dd }

api_response = {'level-1': '1', 'level-2': {'leve2-1': '21',
                    'leve2-2': {'leve3-1': '31', 'leve3-2': {'leve4-1': '41',
                    'level4-2': {'level5-1': '51'}, 'level5-2': '52'}}}}


print(flatten(api_response))

Вывод:

{'level-1': '1', 'level-2_leve2-1': '21', 
'level-2_leve2-2_leve3-1': '31', 
'level-2_leve2-2_leve3-2_leve4-1': '41', 
'level-2_leve2-2_leve3-2_level4-2_level5-1': '51', 
'level-2_leve2-2_leve3-2_level5-2': '52'}
...