Получить ключ по значению в словаре - PullRequest
516 голосов
/ 06 ноября 2011

Я сделал функцию, которая будет искать возраст в Dictionary и показывать соответствующее имя:

dictionary = {'george' : 16, 'amber' : 19}
search_age = raw_input("Provide age")
for age in dictionary.values():
    if age == search_age:
        name = dictionary[age]
        print name

Я знаю, как сравнивать и находить возраст, я просто не знаю, как показатьимя человека.Кроме того, я получаю KeyError из-за строки 5. Я знаю, что это не правильно, но я не могу понять, как заставить его искать в обратном направлении.

Ответы [ 34 ]

493 голосов
/ 31 октября 2012
mydict = {'george':16,'amber':19}
print mydict.keys()[mydict.values().index(16)] # Prints george

Или в Python 3.x:

mydict = {'george':16,'amber':19}
print(list(mydict.keys())[list(mydict.values()).index(16)]) # Prints george

По сути, он разделяет значения словаря в списке, находит позицию имеющегося у вас значения и получает ключ в этой позиции.

Подробнее о keys() и .values() в Python 3: Python: самый простой способ получить список значений из dict?

466 голосов
/ 06 ноября 2011

Там нет ни одного. dict не предназначен для использования таким образом.

for name, age in dictionary.items():    # for name, age in dictionary.iteritems():  (for Python 2.x)
    if age == search_age:
        print(name)
224 голосов
/ 06 ноября 2011

Если вам нужно имя и возраст, вы должны использовать .items(), что дает вам ключ (key, value) кортежей:

for name, age in mydict.items():
    if age == search_age:
        print name

Вы можете распаковать кортеж вдве отдельные переменные прямо в цикле for, а затем совпадают с возрастом.

Вам также следует рассмотреть вопрос об изменении словаря, если вы, как правило, будете искать по возрасту, и нет двух людей одного возраста:

{16: 'george', 19: 'amber'}

чтобы вы могли найти имя для возраста, просто набрав

mydict[search_age]

Я назвал его mydict вместо list, потому что listэто имя встроенного типа, и вы не должны использовать это имя ни для чего другого.

Вы даже можете получить список всех людей с данным возрастом в одну строку:

[name for name, age in mydict.items() if age == search_age]

или если в каждом возрасте есть только один человек:

next((name for name, age in mydict.items() if age == search_age), None)

, который просто даст вам None, если нет людей с таким возрастом.

Наконец,если dict длинный и вы используете Python 2, вам следует рассмотреть возможность использования .iteritems() вместо .items(), как это сделал Cat Plus Plus в своемответ, так как не нужно делать копию списка.

62 голосов
/ 31 января 2013

Я подумал, что было бы интересно указать, какие методы являются самыми быстрыми и в каком сценарии:

Вот несколько тестов, которые я провел (на MacBook Pro 2012 года)

>>> def method1(list,search_age):
...     for name,age in list.iteritems():
...             if age == search_age:
...                     return name
... 
>>> def method2(list,search_age):
...     return [name for name,age in list.iteritems() if age == search_age]
... 
>>> def method3(list,search_age):
...     return list.keys()[list.values().index(search_age)]

Результаты profile.run() для каждого метода 100000 раз:

Метод 1:

>>> profile.run("for i in range(0,100000): method1(list,16)")
     200004 function calls in 1.173 seconds

Метод 2:

>>> profile.run("for i in range(0,100000): method2(list,16)")
     200004 function calls in 1.222 seconds

Метод 3:

>>> profile.run("for i in range(0,100000): method3(list,16)")
     400004 function calls in 2.125 seconds

Таким образом, это показывает, что для небольшого требования метод 1 является самым быстрым.Это, скорее всего, потому что он возвращает первое совпадение, в отличие от всех совпадений, таких как метод 2 (см. Примечание ниже).


Интересно, что те же самые тесты, которые у меня есть, выполняются с 2700 записямиЯ получаю совершенно разные результаты (на этот раз 10000 раз):

Метод 1:

>>> profile.run("for i in range(0,10000): method1(UIC_CRS,'7088380')")
     20004 function calls in 2.928 seconds

Метод 2:

>>> profile.run("for i in range(0,10000): method2(UIC_CRS,'7088380')")
     20004 function calls in 3.872 seconds

Метод 3:

>>> profile.run("for i in range(0,10000): method3(UIC_CRS,'7088380')")
     40004 function calls in 1.176 seconds

Итак, метод 3 намного быстрее .Показывает, что размер вашего dict будет влиять на выбранный вами метод.

Примечания: Метод 2 возвращает список всех имен, тогда как методы 1 и 3 возвращают только первое совпадение.Я не рассматривал использование памяти.Я не уверен, что метод 3 создает 2 дополнительных списка (keys () и values ​​()) и сохраняет их в памяти.

43 голосов
/ 03 октября 2013

однострочная версия: (i - старый словарь, p - обратный словарь)

объяснение: i.keys () и i.values ​​() возвращает два списка с ключами и значениями словаря соответственно,Функция zip имеет возможность связывать списки для создания словаря.

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

p = dict(zip(i.values(),i.keys()))
23 голосов
/ 26 июля 2016
a = {'a':1,'b':2,'c':3}
{v:k for k, v in a.items()}[1]

или лучше

{k:v for k, v in a.items() if v == 1}
19 голосов
/ 11 июля 2012
lKey = [key for key, value in lDictionary.iteritems() if value == lValue][0]
10 голосов
/ 05 августа 2018

Попробуйте этот однострочный, чтобы перевернуть словарь:

reversed_dictionary = dict(map(reversed, dictionary.items()))
10 голосов
/ 07 марта 2016

Ключ можно получить с помощью методов dict.keys(), dict.values() и list.index(), см. Примеры кода ниже:

names_dict = {'george':16,'amber':19}
search_age = int(raw_input("Provide age"))
key = names_dict.keys()[names_dict.values().index(search_age)]
9 голосов
/ 18 декабря 2014

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

lookup = {value: key for key, value in self.data}
lookup[value]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...