Python список словарей поиска - PullRequest
336 голосов
/ 28 декабря 2011

Предположим, у меня есть это:

[
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

и с помощью поиска "Pam" в качестве имени я хочу получить соответствующий словарь: {name: "Pam", age: 7}

Как этого добиться?

Ответы [ 18 ]

380 голосов
/ 28 декабря 2011

Вы можете использовать выражение генератора :

>>> dicts = [
...     { "name": "Tom", "age": 10 },
...     { "name": "Mark", "age": 5 },
...     { "name": "Pam", "age": 7 },
...     { "name": "Dick", "age": 12 }
... ]

>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}
156 голосов
/ 19 августа 2014

Это выглядит для меня наиболее питоническим образом:

people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]

filter(lambda person: person['name'] == 'Pam', people)

результат (возвращается в виде списка в Python 2):

[{'age': 7, 'name': 'Pam'}]

Примечание: в Python 3 объект фильтравозвращаетсяТаким образом, решение python3 будет:

list(filter(lambda person: person['name'] == 'Pam', people))
52 голосов
/ 13 августа 2015

@ Фредерик Хамиди ответил великолепно.В Python 3.x синтаксис для .next() немного изменился.Таким образом, небольшое изменение:

>>> dicts = [
     { "name": "Tom", "age": 10 },
     { "name": "Mark", "age": 5 },
     { "name": "Pam", "age": 7 },
     { "name": "Dick", "age": 12 }
 ]
>>> next(item for item in dicts if item["name"] == "Pam")
{'age': 7, 'name': 'Pam'}

Как уже упоминалось в комментариях @Matt, вы можете добавить значение по умолчанию как таковое:

>>> next((item for item in dicts if item["name"] == "Pam"), False)
{'name': 'Pam', 'age': 7}
>>> next((item for item in dicts if item["name"] == "Sam"), False)
False
>>>
36 голосов
/ 28 декабря 2011

Вы можете использовать список понимания :

def search(name, people):
    return [element for element in people if element['name'] == name]
25 голосов
/ 28 декабря 2011
people = [
{'name': "Tom", 'age': 10},
{'name': "Mark", 'age': 5},
{'name': "Pam", 'age': 7}
]

def search(name):
    for p in people:
        if p['name'] == name:
            return p

search("Pam")
18 голосов
/ 24 февраля 2018

Я протестировал различные методы, чтобы просмотреть список словарей и вернуть словари, в которых ключ x имеет определенное значение.

Результаты:

  • Скорость: понимание списка> выражение генератора >> обычная итерация списка >>> фильтр.
  • Вся линейная шкала с количеством диктов в списке (10х размер списка -> 10х раз).
  • Количество ключей в словаре не оказывает существенного влияния на скорость для большого количества (тысяч) ключей.Пожалуйста, посмотрите график, который я рассчитал: https://imgur.com/a/quQzv (названия методов см. Ниже).

Все тесты выполнены с Python 3.6 .4, W7x64.

from random import randint
from timeit import timeit


list_dicts = []
for _ in range(1000):     # number of dicts in the list
    dict_tmp = {}
    for i in range(10):   # number of keys for each dict
        dict_tmp[f"key{i}"] = randint(0,50)
    list_dicts.append( dict_tmp )



def a():
    # normal iteration over all elements
    for dict_ in list_dicts:
        if dict_["key3"] == 20:
            pass

def b():
    # use 'generator'
    for dict_ in (x for x in list_dicts if x["key3"] == 20):
        pass

def c():
    # use 'list'
    for dict_ in [x for x in list_dicts if x["key3"] == 20]:
        pass

def d():
    # use 'filter'
    for dict_ in filter(lambda x: x['key3'] == 20, list_dicts):
        pass

Результаты:

1.7303 # normal list iteration 
1.3849 # generator expression 
1.3158 # list comprehension 
7.7848 # filter
10 голосов
/ 10 декабря 2015

Чтобы добавить чуть-чуть к @ FrédéricHamidi.

Если вы не уверены, что ключ находится в списке диктов, может помочь что-то вроде этого:

next((item for item in dicts if item.get("name") and item["name"] == "Pam"), None)
8 голосов
/ 02 сентября 2016

Вы когда-нибудь пробовали пакет с пандами?Он идеально подходит для такого рода задач поиска и оптимизирован.

import pandas as pd

listOfDicts = [
{"name": "Tom", "age": 10},
{"name": "Mark", "age": 5},
{"name": "Pam", "age": 7}
]

# Create a data frame, keys are used as column headers.
# Dict items with the same key are entered into the same respective column.
df = pd.DataFrame(listOfDicts)

# The pandas dataframe allows you to pick out specific values like so:

df2 = df[ (df['name'] == 'Pam') & (df['age'] == 7) ]

# Alternate syntax, same thing

df2 = df[ (df.name == 'Pam') & (df.age == 7) ]

Ниже я добавил несколько сравнительных тестов, чтобы проиллюстрировать более быстрое время выполнения панд в более широком масштабе, например, 100 000 записей:

setup_large = 'dicts = [];\
[dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 })) for _ in range(25000)];\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);'

setup_small = 'dicts = [];\
dicts.extend(({ "name": "Tom", "age": 10 },{ "name": "Mark", "age": 5 },\
{ "name": "Pam", "age": 7 },{ "name": "Dick", "age": 12 }));\
from operator import itemgetter;import pandas as pd;\
df = pd.DataFrame(dicts);'

method1 = '[item for item in dicts if item["name"] == "Pam"]'
method2 = 'df[df["name"] == "Pam"]'

import timeit
t = timeit.Timer(method1, setup_small)
print('Small Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_small)
print('Small Method Pandas: ' + str(t.timeit(100)))

t = timeit.Timer(method1, setup_large)
print('Large Method LC: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup_large)
print('Large Method Pandas: ' + str(t.timeit(100)))

#Small Method LC: 0.000191926956177
#Small Method Pandas: 0.044392824173
#Large Method LC: 1.98827004433
#Large Method Pandas: 0.324505090714
6 голосов
/ 28 декабря 2011
names = [{'name':'Tom', 'age': 10}, {'name': 'Mark', 'age': 5}, {'name': 'Pam', 'age': 7}]
resultlist = [d    for d in names     if d.get('name', '') == 'Pam']
first_result = resultlist[0]

Это один из способов ...

6 голосов
/ 20 июля 2014

Это общий способ поиска значения в списке словарей:

def search_dictionaries(key, value, list_of_dictionaries):
    return [element for element in list_of_dictionaries if element[key] == value]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...