#python #python-3.x
Вопрос:
У меня есть объект в Python 3 такого формата:
a = {
'events': [
{
'timestamp': 123,
'message': 'test'
},
{
'timestamp': 456,
'message': 'foo'
},
{
'timestamp': 789,
'message': 'testbar'
},
],
'first': 'abc',
'last': 'def'
}
Я хочу создать новый объект того же формата, но отфильтрованный по тому, содержит ли соответствующее message
значение ключа определенную строку, например, отфильтровав по "test"
:
a = {
'events': [
{
'timestamp': 123,
'message': 'test'
},
{
'timestamp': 789,
'message': 'testbar'
},
],
'first': 'abc',
'last': 'def'
}
Могу ли я использовать для этого вложенное понимание? Я знаю, что вы можете выполнять понимание вложенных списков, например:
[[y*2 for y in x] for x in l]
Но есть ли аккуратный выход dict > list > dict
из ситуации?
Комментарии:
1. Вы можете использовать понимание списка для событий . Более общее решение
dict
будет зависеть от удобочитаемости/ремонтопригодности.
Ответ №1:
Одним из вариантов может быть создание новой копии входного диктанта без событий, а затем установка отфильтрованных событий по вашему требованию, например:
copy = {k: v for k, v in a.items() if k != 'events'}
copy['events'] = [e for e in a['events'] if 'test' in e['message']]
Или, если вы не возражаете против перезаписи исходных данных, просто сделайте это:
a['events'] = [e for e in a['events'] if 'test' in e['message']]
Ответ №2:
Я бы пошел с пониманием списка с помощью if-утверждения, подобного следующему:
[event for event in a["events"] if event["message"] == "test" ]
Просмотрите значения "events"
-ключа и добавьте их в список, если значение их "message"
ключа равно "test"
.
В результате вы получите список словарей, которые вы можете назначить обратно a["events"]
, или копию a
, если хотите сохранить a["events"]
.
Ответ №3:
Итак, вы можете использовать несколько уровней понимания, но это не значит, что вы должны это делать. Я думаю, что для такого примера вы бы создали более чистый код, запустив его через пару циклов for. Сказав это, я думаю, что следующее технически достигает результата, о котором вы просите.
>>> pprint.pprint(a)
{'events': [{'message': 'test', 'timestamp': 123},
{'message': 'foo', 'timestamp': 456},
{'message': 'testbar', 'timestamp': 789}],
'first': 'abc',
'last': 'def'}
>>> aa = copy.deepcopy(a)
>>> aa['beta'] = aa['events']
>>> pprint.pprint({k:[item for item in v if 'test' in item['message']] if isinstance(v, list) else v for k, v in aa.items()})
{'beta': [{'message': 'test', 'timestamp': 123},
{'message': 'testbar', 'timestamp': 789}],
'events': [{'message': 'test', 'timestamp': 123},
{'message': 'testbar', 'timestamp': 789}],
'first': 'abc',
'last': 'def'}
>>> pprint.pprint({k:[item for item in v if 'test' in item['message']] if isinstance(v, list) else v for k, v in a.items()})
{'events': [{'message': 'test', 'timestamp': 123},
{'message': 'testbar', 'timestamp': 789}],
'first': 'abc',
'last': 'def'}
Как уже было сказано, это то, что вы можете сделать; однако я бы от имени всех, кому приходилось читать код других людей в своей карьере, с уважением попросил вас не использовать это в производственном коде. Пара циклов for может быть более локальными, но в большинстве случаев они будут гораздо более удобочитаемыми и обслуживаемыми.