Найти элемент в списке словарей

У меня есть эти данные

data = [
    {
        'id': 'abcd738asdwe',
        'name': 'John',
        'mail': 'test@test.com',
    },
    {
        'id': 'ieow83janx',
        'name': 'Jane',
        'mail': 'test@foobar.com',
    }
]

Идентификаторы уникальны, невозможно, чтобы несколько словарей имели один и тот же идентификатор.

Например, я хочу получить элемент с идентификатором ieow83janx.

Мое текущее решение выглядит так:

search_id = 'ieow83janx'
item = [x for x in data if x['id'] == search_id][0]

Как вы думаете, это подходящее решение или кто-нибудь знает альтернативное решение?

загрузить словарь в объект json и получить доступ к содержимому на основе идентификатора?

Surya Tej 13.09.2018 20:21

Насколько велик набор данных и сколько раз вы повторяете список? Возможно, стоит сделать один проход и создать новый словарь с id в качестве ключей.

roganjosh 13.09.2018 20:22

Размер варьируется, но не может быть больше 20 штук.

Nepo Znat 13.09.2018 20:25

Зачем проверять каждый ключ, если вас интересует только первое совпадение?

Stop harming Monica 13.09.2018 22:52
1
4
101
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Поскольку id уникальны, вы можете хранить элементы в словаре, чтобы выполнить поиск O (1).

lookup = {ele['id']: ele for ele in data}

тогда ты можешь сделать

user_info = lookup[user_id]

получить это

Если вы собираетесь выполнять такого рода операции с этим конкретным объектом более одного раза, я бы рекомендовал перевести его в словарь с id в качестве ключа.

data = [
    {
        'id': 'abcd738asdwe',
        'name': 'John',
        'mail': 'test@test.com',
    },
    {
        'id': 'ieow83janx',
        'name': 'Jane',
        'mail': 'test@foobar.com',
    }
]

data_dict = {item['id']: item for item in data}
#=> {'ieow83janx': {'mail': 'test@foobar.com', 'id': 'ieow83janx', 'name': 'Jane'}, 'abcd738asdwe': {'mail': 'test@test.com', 'id': 'abcd738asdwe', 'name': 'John'}}

data_dict['ieow83janx']
#=> {'mail': 'test@foobar.com', 'id': 'ieow83janx', 'name': 'Jane'}

В этом случае эта операция поиска будет стоить вам постоянного времени * O(1) вместо O(N).

Это отличное решение. Я не думал об этом. Ничего страшного, если я просто напишу это? item = {item ['id']: элемент для элемента в данных} ['ieow83janx']

Nepo Znat 13.09.2018 20:33

Без создания нового словаря или написания нескольких строк кода вы можете просто использовать встроенную функцию filter для ленивого получения элемента, не проверяя после того, как он найдет совпадение.

next(filter(lambda d: d['id']==search_id, data))

должен просто отлично.

next(entry for entry in data if entry['id'] == search_id)
Peter Wood 13.09.2018 20:29

Как насчет встроенной функции next (документы):

>>> data = [
...     {
...         'id': 'abcd738asdwe',
...         'name': 'John',
...         'mail': 'test@test.com',
...     },
...     {
...         'id': 'ieow83janx',
...         'name': 'Jane',
...         'mail': 'test@foobar.com',
...     }
... ]
>>> search_id = 'ieow83janx'
>>> next(x for x in data if x['id'] == search_id)
{'id': 'ieow83janx', 'name': 'Jane', 'mail': 'test@foobar.com'}

Обновлено:

Он вызывает StopIteration, если совпадений не найдено, что является прекрасным способом справиться с отсутствием:

>>> search_id = 'does_not_exist'
>>> try:
...     next(x for x in data if x['id'] == search_id)
... except StopIteration:
...     print('Handled absence!')
... 
Handled absence!

@ fl00r Да, и обработка ошибки, на мой взгляд, самый питонический способ справиться с любыми пропусками.

Cole 13.09.2018 20:32

Я даже не знал, что эта функция существует. Спасибо за ответ

Nepo Znat 13.09.2018 20:35

@sascha Нет проблем, проверьте обновления, чтобы узнать, как вы можете справиться с отсутствием.

Cole 13.09.2018 20:36
if any(item['id']=='ieow83janx' for item in data):
   #return item

Поскольку любая функция возвращает истину, если итерабельность (список словарей в вашем случае) имеет значение. При использовании Generator Expression создавать внутренний список не нужно. Поскольку в Списке словарей не будет повторяющихся значений для идентификатора, любое из них остановит итерацию до тех пор, пока условие не вернет истину. то есть выражение генератора с любым перестанет повторяться при коротком замыкании. Использование понимания списка создаст весь список в памяти, где GE создает элемент на лету, что будет лучше, если у вас есть большие элементы, поскольку он использует меньше памяти.

Хотя это может ответить на вопрос авторов, в нем отсутствуют некоторые поясняющие слова и ссылки на документацию. Фрагменты исходного кода не очень полезны без некоторых фраз. Вы также можете найти как написать хороший ответ очень полезным. Пожалуйста, отредактируйте свой ответ.

hellow 14.09.2018 08:09

Спасибо @hellow добавил пояснение к ответу.

Shubham Sharma 16.09.2018 07:28

Разве это не достигнет вашей цели?

for i in data:
    if i.get('id') == 'ieow83janx':
        print(i)
(xenial)vash@localhost:~/python$ python3.7 split.py 
{'id': 'ieow83janx', 'name': 'Jane', 'mail': 'test@foobar.com'}

Используя понимание:

[i for i in data if i.get('id') == 'ieow83janx']

Другие вопросы по теме