#python #recursion
Вопрос:
У меня есть такой json:
{
"result": [
{
"timestamp": 1234567890,
"textsList": [
{
"text": "some text here 0"
}
],
"otherList": [
{
"type": "Nothing"
},
{
"type": "Recursive",
"data": {
"timestamp": 12345678901234,
"textsList": [
{
"text": "some other text 1"
}
],
"otherList": [
{
"type": "Nothing"
},
{
"type": "Recursive",
"data": {
"timestamp": 12345678901234,
"textsList": [
{
"text": "some other text 2"
}
],
"otherList": []
}
}
]
}
}
]
}
]
}
Я пытаюсь извлечь новый json, подобный этому:
[{
"timestamp": 1234567890,
"text": "some text here 0"
},
{
"timestamp": 12345678901234,
"text": "some other text 1"
},
{
"timestamp": 1234567890,
"text": "some other text 2"
}
]
поскольку список других может быть бесконечным, я пытаюсь использовать рекурсивную функцию. к сожалению, мне кажется, что я чего-то не понимаю.
Это моя основная функция для получения данных:
def getText (element):
textData = {
"timestamp": element["timestamp"],
"text": element["textList"][0]["text"],
}
return textData
затем в main.py Я вызываю команду «для», чтобы передать каждый результат, я помещаю метку времени и текст в список, например:
for el in jsonFile:
textData = getText(jsonresult)
и после этого я должен запустить рекурсивный для всех элементов в списке других, но я не понимаю, как это сделать.
Комментарии:
1. Чтобы это была рекурсивная функция, вам нужно было бы иногда включать вызов функции изнутри самой функции.
2. да, я знаю это, действуйте в main.py (внутри for) я помещаю рекурсивный вызов, но я не понимаю, как поместить результаты в массив текстовых данных. Я не сообщал о тестируемой функции
3. В
main.py
-это не то же самое, что внутри самой функции.4. ммм, я не понимаю, что ты имеешь в виду
5. Вот однострочная рекурсивная функция, которая создает список с обратным отсчетом от n:
def count(n): return [n] count(n-1) if n > 0 else []
Смотрите, как функция включает вызов самой себе?
Ответ №1:
с помощью рекурсии вы можете сделать что-то подобное:
result = []
def finditem(obj, key):
if key in obj: result.append({"timestamp": obj[key], "text": obj['textsList'][0]['text']})
for k, v in obj.items():
if isinstance(v,dict):
item = finditem(v, key)
if item is not None:
result.append({"timestamp": item,"text":v['textsList'][0]['text']})
elif isinstance(v,list):
for i in v:
item = finditem(i, key)
if item is not None:
result.append({"timestamp": item,"text": i['textsList'][0]['text']})
finditem(data, 'timestamp')
print (result)
Результат:
[{'timestamp': 1234567890, 'text': 'some text here 0'}, {'timestamp': 12345678901234, 'text': 'some other text 1'}, {'timestamp': 12345678901234, 'text': 'some other text 2'}]
Редактировать:
result = []
def finditem(obj, key):
if key in obj and obj[key]=='Recursive': result.append({"timestamp": obj["data"]["timestamp"],"text": obj["data"]['textsList'][0]['text']})
for k, v in obj.items():
if isinstance(v,dict):
item = finditem(v, key)
if item == 'Recursive':
d = v['timestamp']
result.append({"timestamp": d,"text": v['textsList'][0]['text']})
elif isinstance(v,list):
for list_item in v:
item = finditem(list_item, key)
if item == 'Recursive':
d = list_item['timestamp']
result.append({"timestamp": d,"text": list_item['textsList'][0]['text']})
finditem(data,'type')
print (result)
Результат:
[{'timestamp': 12345678901234, 'text': 'some other text 1'}, {'timestamp': 12345678901234, 'text': 'some other text 2'}]
Комментарии:
1. вместо проверки метки времени это можно сделать, учитывая, является ли «тип» «Рекурсивным» ? так как иногда метка времени присутствует даже в типе ничего….но для полноты я удалил ее в примере json
2. кроме того, я получаю сообщение об ошибке «список» объект не имеет атрибута «элементы»
3. @alexmark Я отредактировал сообщение, я добавил новый код, который выполняет рекурсивный поиск, учитывая, является ли «тип» «Рекурсивным».
Ответ №2:
Каждая запись в списке (те, что в квадратных скобках), по-видимому, содержит:
- отметка времени
- текст
- другой список
Поэтому вам нужно изменить getText, чтобы сделать две вещи
- измените метод для получения более одного результата TextData (например, сохраните результаты в списке).
- добавьте код для работы с записью otherlist в дополнение к метке времени и текстовым записям
Вот так:
def getText (element, resultList):
textData = {
"timestamp": element["timestamp"],
"text": element["textsList"][0]["text"],
}
resultList.append(textData)
otherList = element["otherList"]
<insert method call to parse otherList into resultList here>
Далее вам нужно добавить метод для повторения списка других.
def processOtherList(data, resultList):
for el in data:
if "type" in el and el["type"] == "Recursive":
getText(el["data"], resultList)
Поэтому вставьте это в метод getText ранее:
def getText (element, resultList):
textData = {
"timestamp": element["timestamp"],
"text": element["textsList"][0]["text"],
}
resultList.append(textData)
otherList = element["otherList"]
processOtherList(otherList, resultList)
И, наконец, исправьте main.py:
results = []
for el in jsonFile["result"]:
getText(el, results)
Окончательный результат:
Комментарии:
1. а итоговый список? Я должен вызвать resultlist = ParseData(jsonFile) с возвращением в ParseData?
2. кроме того, должно быть что-то вроде: если «тип» не в el или el[«тип»] == «Рекурсивный»
3. Я внес некоторые изменения, проверьте ссылку на конечный результат для полностью работающего образца.
Ответ №3:
Вы можете использовать рекурсивную функцию генератора:
def get_text(d):
if isinstance(d, dict):
if 'timestamp' in d:
yield {'timestamp':d['timestamp'], 'textsList':''.join(i['text'] for i in d['textsList'])}
for b in d.values():
yield from get_text(b)
elif isinstance(d, list):
yield from [i for j in d for i in get_text(j)]
data = {'result': [{'timestamp': 1234567890, 'textsList': [{'text': 'some text here 0'}], 'otherList': [{'type': 'Nothing'}, {'type': 'Recursive', 'data': {'timestamp': 12345678901234, 'textsList': [{'text': 'some other text 1'}], 'otherList': [{'type': 'Nothing'}, {'type': 'Recursive', 'data': {'timestamp': 12345678901234, 'textsList': [{'text': 'some other text 2'}], 'otherList': []}}]}}]}]}
print(list(get_text(data)))
Выход:
[{'timestamp': 1234567890, 'textsList': 'some text here 0'},
{'timestamp': 12345678901234, 'textsList': 'some other text 1'},
{'timestamp': 12345678901234, 'textsList': 'some other text 2'}]