Создать вложенный объект JSON из списка диктов - PullRequest
1 голос
/ 02 апреля 2019

Я хочу перевести список словарей во вложенный .json объект файла. У меня есть список словарей, и одно из полей в словаре указывает, следует ли вкладывать конкретное поле в файл .json, и если да, то в этом файле.

Я могу вкладывать вещи в соответствующую таблицу, но заставляя их вкладываться дальше в полях, я зацикливаюсь.

мои данные поступают в следующем формате:

table_list = [
    {"Table": "table1", "Field": "field1", "Description": "description1", "Type": "STR"}, 
    {"Table": "table1", "Field": "field2", "Description": "description2", "Type": "STR"}, 
    {"Table": "table1", "Field": "field3", "Description": "description3", "Type": "STR"},
    {"Table": "table1", "Field": "field4", "Description": "description4", "Type": "STR"},
    {"Table": "table1", "Field": "field5", "Description": "description5", "Type": "RECORD"},
    {"Table": "table1", "Field": "field5.nest1", "Description": "description6", "Type": "STR"},
    {"Table": "table1", "Field": "field5.nest2", "Description": "description7", "Type": "STR"},
    {"Table": "table1", "Field": "field5.nest3", "Description": "description8", "Type": "STR"},
    {"Table": "table1", "Field": "field5.nest4", "Description": "description9", "Type": "RECORD"},
    {"Table": "table1", "Field": "field5.nest4.nest1", "Description": "description10", "Type": "STR"},
    {"Table": "table1", "Field": "field5.nest4.nest2", "Description": "description11", "Type": "STR"},
    {"Table": "table2", "Field": "field1", "Description": "description1", "Type": "STR"}
]

и я хотел бы вывести его в этот формат (извините за опечатки):

{
    "table1": [
    {
        "Field": "field1",
        "Description": "description1",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "field2",
        "Description": "description2",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "field3",
        "Description": "description3",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "field4",
        "Description": "description4",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "field5",
        "Description": "description5",
        "Mode": "REPEATED",
        "Type": "RECORD",
        "Fields": [
            {
                "Field": "nest1",
                "Description": "description6",
                "Mode": "NULLABLE",
                "Type": "STR"
            },
            {
                "Field": "nest2",
                "Description": "description7",
                "Mode": "NULLABLE",
                "Type": "STR"
            },
            {
                "Field": "nest3",
                "Description": "description8",
                "Mode": "NULLABLE",
                "Type": "STR"
            },
            {
                "Field": "nest4",
                "Description": "description9",
                "Mode": "REPEATED",
                "Type": "RECORD",
                "Fields": [
                    {
                        "Field": "nest1",
                        "Description": "description10",
                        "Mode": "NULLABLE",
                        "Type": "STR"
                    },
                    {
                        "Field": "nest2",
                        "Description": "description11",
                        "Mode": "NULLABLE",
                        "Type": "STR"
                    }
                ]
            }
        ]
    }
    ]
    "table2": [
    {
        "Field": "field1",
        "Description": "description1",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    ]
}

и у меня возникают проблемы с получением nest1 и nest2 для создания нового поля в существующем dict с открытым списком, который можно добавить на глубину перемещения. Гнезда в этом примере идут только на 3 глубины, но мне может понадобиться пройти до 15 уровней глубиной .

У меня есть код, который будет применять его на первом уровне с "Table", но входить в поля для добавления в этот список было непросто, и я не нашел вопрос с точно такой же проблемой.

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

import json


def create_schema(file_to_read):
    all_tables = {}
    for row in file_to_read:
        if row['Table'] in all_tables.keys():
            all_tables[row['Table']].append({"Mode": "NULLABLE",
                                             "Field": row['Field'],
                                             "Type": row['Type'],
                                             "Description": row['Description']})
        else:
            all_tables[row['Table']] = []
            all_tables[row['Table']].append({"Mode": "NULLABLE",
                                             "Field": row['Field'],
                                             "Type": row['Type'],
                                             "Description": row['Description']})
    return json.dumps(all_tables, indent=4, sort_keys=True)

что я на самом деле получаю с помощью этой функции:

{
    "table1": [
    {
        "Field": "field1",
        "Description": "description1",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "field2",
        "Description": "description2",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "field3",
        "Description": "description3",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "field4",
        "Description": "description4",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "field5",
        "Description": "description5",
        "Mode": "NULLABLE",
        "Type": "RECORD",
    },
    {
        "Field": "nest1",
        "Description": "description6",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "nest2",
        "Description": "description7",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "nest3",
        "Description": "description8",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "nest4",
        "Description": "description9",
        "Mode": "NULLABLE",
        "Type": "RECORD",
    },
    {
        "Field": "nest1",
        "Description": "description10",
        "Mode": "NULLABLE",
        "Type": "STR"
    },
    {
        "Field": "nest2",
        "Description": "description11",
        "Mode": "NULLABLE",
        "Type": "STR"
    }
    ]
    "table2": [
    {
        "Field": "field1",
        "Description": "description1",
        "Mode": "NULLABLE",
        "Type": "STR"
    }
    ]
}

(Для контекста это подразумевается как схема BigQuery JSON)

1 Ответ

1 голос
/ 02 апреля 2019

Это должно сделать то, что вы хотите сделать:

from collections import defaultdict

d = defaultdict(list)
for t in table_list:
    field_list = d[t['Table']]
    field = t['Field'].split('.')
    for f in field[:-1]:
        field_list = next(el['Fields'] for el in field_list if el['Field'] == f)
    new_d = {'Field': field[-1], 'Description': t['Description'], 'Mode': 'NULLABLE' if t['Type'] == 'STR' else 'REPEATED', 'Type': t['Type']}
    field_list.append(defaultdict(list, new_d))

print(json.dumps(d, indent=4))

Или, если вы предпочитаете избегать defaultdict:

d = {}
for t in table_list:
    if t['Table'] not in d:
        d[t['Table']] = []
    field_list = d[t['Table']]
    field = t['Field'].split('.')
    for f in field[:-1]:
        inner = next(el for el in field_list if el['Field'] == f)
        if 'Fields' not in inner:
            inner['Fields'] = []
        field_list = inner['Fields']
    new_d = {'Field': field[-1], 'Description': t['Description'], 'Mode': 'NULLABLE' if t['Type'] == 'STR' else 'REPEATED', 'Type': t['Type']}
    field_list.append(new_d)

Вывод:

{
    "table1": [
        {
            "Field": "field1",
            "Description": "description1",
            "Mode": "NULLABLE",
            "Type": "STR"
        },
        {
            "Field": "field2",
            "Description": "description2",
            "Mode": "NULLABLE",
            "Type": "STR"
        },
        {
            "Field": "field3",
            "Description": "description3",
            "Mode": "NULLABLE",
            "Type": "STR"
        },
        {
            "Field": "field4",
            "Description": "description4",
            "Mode": "NULLABLE",
            "Type": "STR"
        },
        {
            "Field": "field5",
            "Description": "description5",
            "Mode": "REPEATED",
            "Type": "RECORD",
            "Fields": [
                {
                    "Field": "nest1",
                    "Description": "description6",
                    "Mode": "NULLABLE",
                    "Type": "STR"
                },
                {
                    "Field": "nest2",
                    "Description": "description7",
                    "Mode": "NULLABLE",
                    "Type": "STR"
                },
                {
                    "Field": "nest3",
                    "Description": "description8",
                    "Mode": "NULLABLE",
                    "Type": "STR"
                },
                {
                    "Field": "nest4",
                    "Description": "description9",
                    "Mode": "REPEATED",
                    "Type": "RECORD",
                    "Fields": [
                        {
                            "Field": "nest1",
                            "Description": "description10",
                            "Mode": "NULLABLE",
                            "Type": "STR"
                        },
                        {
                            "Field": "nest2",
                            "Description": "description11",
                            "Mode": "NULLABLE",
                            "Type": "STR"
                        }
                    ]
                }
            ]
        }
    ],
    "table2": [
        {
            "Field": "field1",
            "Description": "description1",
            "Mode": "NULLABLE",
            "Type": "STR"
        }
    ]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...