#arrays #json #python-3.x
Вопрос:
Я пытаюсь отфильтровать массив Json с помощью Python на основе нескольких условий. Мой Json похож на этот (без корневого имени):
{
"id": "123455",
"outter": {
"inner": [
{
"nox": "abc:6666",
"code": "1329",
}
],
},
"topic": {
"reference": "excel"
},
"date1": "1990-07-28T03:52:44-04:00",
"finalDate": "1990-07-28T03:52:44-04:00"
}
{
"id": "123435",
"outter": {
"inner": [
{
"nox": "abc:6666",
"code": "9351",
}
],
},
"topic": {
"reference": "excel"
},
"date1": "1990-07-28T03:52:44-04:00",
"finalDate": "1995-07-28T03:52:44-04:00"
}
Моя цель состоит в том, чтобы отфильтровать на основе 2 условий и вернуть все, что им соответствует.
1: внешний —> внутренний —>> код = 9351 И
2: Окончательная дата >= 1995
До сих пор я могу выполнить эту проверку отдельно без проблем со следующим кодом:
data = pd.read_json('myFile.ndjson', lines = True)
for item in data['outter']:
for x in item['inner']:
if(x['code'] == '9351'):
found....
но не уверен, как сделать и то, и другое одновременно, так как я должен начать цикл с или data['outter']
или data['finalDate']
, и внутри цикла у меня есть видимость только этого элемента массива, а не всего массива.
Любая помощь приветствуется, спасибо!
Комментарии:
1. у вас есть небольшая опечатка — поскольку похоже, что у вас есть массив json, вы можете обернуть входной json фигурными скобками
[]
и отделить элементы запятой. Также по совпадению это может использоваться какlist
объект Python как есть.
Ответ №1:
Вот одно из решений, которое может отфильтровать список, как уже упоминалось. Я использую понимание списков вместо циклов, и, вероятно, там есть кое-что, что можно было бы улучшить, но результат, по крайней мере, выглядит так, как ожидалось.
Примечание: При этом используется оператор walrus :=
, который представлен в Python 3.8. Если вы работаете в более ранней версии Python, вы, вероятно, можете удалить код, который его использует, но в этом случае я не слишком беспокоился.
from pprint import pprint
data_list = [
{
"id": "123455",
"outter": {
"inner": [
{
"nox": "abc:6666",
"code": "1329",
}
],
},
"topic": {
"reference": "excel"
},
"date1": "1990-07-28T03:52:44-04:00",
"finalDate": "1990-07-28T03:52:44-04:00"
},
{
"id": "123435",
"outter": {
"inner": [
{
"nox": "abc:6666",
"code": "9351",
}
],
},
"topic": {
"reference": "excel"
},
"date1": "1990-07-28T03:52:44-04:00",
"finalDate": "1995-07-28T03:52:44-04:00"
}
]
result = [d for d in data_list
if (year := d['finalDate'][:4]).isnumeric() and year >= '1995'
and any(str(inner['code']) == '9351'
for inner in d['outter']['inner'] or [])]
pprint(result)
@ted сделал хорошее замечание о том, что важна читабельность, поэтому у меня было некоторое время, чтобы вернуться и написать его в типичном формате цикла (по сути, та же логика, что и выше). Я также много комментариев, чтобы, надеюсь, прояснить, что происходит в коде, надеюсь, вы найдете это полезным 🙂
from pprint import pprint
from typing import Dict, List
result = []
# Looping over each dictionary in list
for d in data_list:
# Grab the year part, first four characters of `finalDate`
year = d['finalDate'][:4]
# isnumeric() to confirm the year part is an an integer
# then check if string (now confirmed to be numeric) has a higher
# ASCII value than 1995.
valid_year = year.isnumeric() and year >= '1995'
# Simple, if it doesn't match our desired year then continue
# with next loop iteration
if not valid_year:
continue
# Get inner list, then loop over it
inner_list: List[Dict] = d['outter']['inner']
for inner in inner_list:
if inner['code'] == '9351':
# We found an inner with our desired code!
break
# The for-else syntax is pretty self-explanatory. This `else` statement is
# only run when we don't `break` out of the loop above.
else:
# No break statement was run, so the desired code did not match
# any elements. Again, continue with the next iteration.
continue
# At this point, we know it's valid since it matched both our
# conditions, so we add it to the result list.
result.append(d)
# Print the result, but it should be the same
pprint(result)
Комментарии:
1. Хотя это может решить проблему, я считаю, что причудливый однострочный список понимания с несколькими встроенными условиями и операторами моржей может быть не очень ясным решением для человека, задающего вопрос, чтобы понять и улучшить. «Красивое лучше, чем уродливое. Явное лучше, чем неявное. Простое лучше, чем сложное. Сложное лучше, чем сложное. Плоская лучше, чем вложенная. Разреженное лучше, чем плотное. Читабельность имеет значение».
2. Да, замечание принято. Хотя я и попытался разбить его на несколько строк для удобства чтения, чтобы ни одна строка не была слишком длинной, оглядываясь назад, используя понимание списка и операторы моржа, чтобы решить проблему как можно быстрее — возможно, это было не самое ясное решение в целом.
3. @ted Я обновил свой ответ, чтобы предоставить альтернативное решение, которое работает для
4. @rv.kvetch, при выполнении вашего кода я получаю следующее: «Ошибка типа: строковые индексы должны быть целыми числами» для строки —> год = d [‘Дата записи’] [: 4] …в этом случае d настраивает только имена узлов id, внешний, внутренний, тема, дата1, конечная дата … чего может не хватать?
5. @rv.kvetch, да, это была строка json. Я использовал json. загружайте, как вы рекомендовали, и работайте, как ожидалось. Спасибо!!!
Ответ №2:
Попробуйте что-нибудь вроде этого.. Меняйте фильтры в соответствии с вашими потребностями 🙂
for item in data:
if item['finalDate'].startswith("1995"):
for inner in item['outter']['inner']:
if inner['code'] == '9351':
print(item)
Комментарии:
1. Это будет работать только для окончательной даты с годом
1995
🙂