#python #json #data-structures #nested
Вопрос:
Используя python, я пытаюсь извлечь поля с именами «первый», «последний» и «почтовый индекс» и их соответствующие значения из JSON, где структура не всегда известна. Пример JSON может выглядеть примерно так:
{
"employees": [
{
"first": "Alice",
"last_name": "Alast",
"zipcode": "12345",
"role": "dev",
"nbr": 1,
"team": [
{
"first_name": "fn",
"last_name": "ln"
},
{
"first_name": "fn2",
"last_name": "ln2"
}
]
},
{
"name": "Bob",
"role": "dev",
"nbr": 2
}
],
"firm": {
"last_name": "Lhans",
"zipcode": "67890",
"location": "CA"
}}
В дополнение к этому я хочу сохранить это в структуре данных, такой как:
{
{
first: "firstname",
last: "lastname",
zipcode: "zipcode"
}
}
Я попытался сгладить вложенный JSON, основываясь на этой функции. Я могу получить поля таким образом, но мне трудно найти оптимальный способ сохранения этих данных в формате модели, упомянутой выше. Если одно из полей пусто, я хочу заполнить это поле как NaN или пустую строку, а не полностью игнорировать его. Вот что у меня есть до сих пор, которое создает список полей и значений, но если поле не существует, оно пропускает его вместо заполнения значением «нет».
def flatten_json(nested_json, fields: list):
out = []
def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], a)
elif type(x) is list:
i = 0
for a in x:
flatten(a)
i = 1
elif name in fields:
out.append(name ": " x)
flatten(nested_json)
return out
Это дает мне что-то вроде:
['first: Alice', 'last: Jones', 'zipcode: 12345', 'first: fn1', 'last: ln1', 'first: fn2', 'last: ln2', 'last: ln3', 'zipcode: 67890']
Что не идеально. Я бы предпочел, чтобы все отсутствующие поля были заполнены NaN или пустой строкой, а не отсутствовали в списке.
Комментарии:
1. Как выглядит JSON, который вы пытаетесь «сгладить»?
2. @ScottHunter только что обновил мой вопрос примером JSON. Но это не всегда будет такой точный формат, и кардинальность расположения полей может измениться.
Ответ №1:
Я изменил вашу функцию, чтобы захватить список словарей. Словарь будет содержать только поля, указанные в списке полей в качестве ключей.
import pandas as pd
def flatten_json(nested_json, fields):
out = []
temp = {}
def flatten(x, name=''):
nonlocal temp
if type(x) is dict:
temp = {}
for a in x:
flatten(x[a], a)
elif type(x) is list:
for i, a in enumerate(x):
flatten(a)
i = 1
elif name in fields:
temp[name] = x
out.append(temp)
flatten(nested_json)
return out
json1 = {"employees": [{"first": "Alice", "last_name": "Alast", "zipcode": "12345", "role": "dev", "nbr": 1, "team": [{"first_name": "fn", "last_name": "ln"}, {
"first_name": "fn2", "last_name": "ln2"}]}, {"name": "Bob", "role": "dev", "nbr": 2}], "firm": {"last_name": "Lhans", "zipcode": "67890", "location": "CA"}}
fields = ['first_name', 'last_name', 'zipcode']
result = (flatten_json(json1, fields))
Выходные данные вышеуказанной функции затем могут быть загружены в фрейм данных pandas —
df = pd.DataFrame(result)
df.drop_duplicates(inplace=True)
print(df)
что даст такой результат —
last_name zipcode first_name
0 Alast 12345 NaN
2 ln NaN fn
4 ln2 NaN fn2
6 Lhans 67890 NaN
Теперь, чтобы получить данные обратно в формате JSON, вы можете преобразовать фрейм данных обратно в dict с помощью функции to_dict() —
print(df.to_dict(orient='records'))
выход-
[{'first_name': nan, 'last_name': 'Alast', 'zipcode': '12345'},
{'first_name': 'fn', 'last_name': 'ln', 'zipcode': nan},
{'first_name': 'fn2', 'last_name': 'ln2', 'zipcode': nan},
{'first_name': nan, 'last_name': 'Lhans', 'zipcode': '67890'}]
Комментарии:
1. Спасибо, это именно то, чего я пытался достичь.