Получить ключ по значению в словаре
Я сделал функцию, которая будет искать возрастов в 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. Я знаю, что это не правильно, но я не могу понять, как заставить его искать в обратном направлении.
30 ответов:
нет.
dict
не предназначен для использования таким образом.for name, age in dictionary.items(): # for name, age in dictionary.iteritems(): (for Python 2.x) if age == search_age: print(name)
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?
если вы хотите, чтобы имя и возраст, вы должны использовать
.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
is долго и вы находитесь на Python 2, вы должны рассмотреть возможность использования.iteritems()
вместо.items()
как Cat Plus Plus сделал в своем ответе, так как ему не нужно делать копию списка.
я подумал, что было бы интересно указать, какие методы являются самыми быстрыми, и в каком сценарии:
вот некоторые тесты, которые я провел (на 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 много быстрее. Просто идет, чтобы показать размер вашего дикт будет влиять на какой метод вы выбирать.
заметки: Метод 2 возвращает список все имена, тогда как методы 1 и 3 возвращают только первое совпадение. Я не рассматривал использование памяти. Я не уверен, что метод 3 создает 2 дополнительных списка (ключи () и значения ()) и сохраняет их в памяти.
однострочная версия: (i-Старый словарь, p-перевернутый словарь)
пояснение: i. keys() и i.values () возвращает два списка с ключами и значениями словаря соответственно. Функция zip имеет возможность связывать вместе списки для создания словаря.
предупреждение : это будет работать только если значения hashable и уникальным.
p = dict(zip(i.values(),i.keys()))
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}
вот мой взгляд на эту проблему. :) Я только начал изучать Python, поэтому я называю это:
"понятное для начинающих" решение.
#Code without comments. list1 = {'george':16,'amber':19, 'Garry':19} search_age = raw_input("Provide age: ") print search_age = int(search_age) listByAge = {} for name, age in list1.items(): if age == search_age: age = str(age) results = name + " " +age print results age2 = int(age) listByAge[name] = listByAge.get(name,0)+age2 print print listByAge
.
#Code with comments. #I've added another name with the same age to the list. list1 = {'george':16,'amber':19, 'Garry':19} #Original code. search_age = raw_input("Provide age: ") print #Because raw_input gives a string, we need to convert it to int, #so we can search the dictionary list with it. search_age = int(search_age) #Here we define another empty dictionary, to store the results in a more #permanent way. listByAge = {} #We use double variable iteration, so we get both the name and age #on each run of the loop. for name, age in list1.items(): #Here we check if the User Defined age = the age parameter #for this run of the loop. if age == search_age: #Here we convert Age back to string, because we will concatenate it #with the person's name. age = str(age) #Here we concatenate. results = name + " " +age #If you want just the names and ages displayed you can delete #the code after "print results". If you want them stored, don't... print results #Here we create a second variable that uses the value of #the age for the current person in the list. #For example if "Anna" is "10", age2 = 10, #integer value which we can use in addition. age2 = int(age) #Here we use the method that checks or creates values in dictionaries. #We create a new entry for each name that matches the User Defined Age #with default value of 0, and then we add the value from age2. listByAge[name] = listByAge.get(name,0)+age2 #Here we print the new dictionary with the users with User Defined Age. print print listByAge
.
#Results Running: *\test.py (Thu Jun 06 05:10:02 2013) Provide age: 19 amber 19 Garry 19 {'amber': 19, 'Garry': 19} Execution Successful!
вы можете получить ключ с помощью
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)]
Если вы хотите найти ключ по значению, вы можете использовать понимание словаря для создания словаря поиска, а затем использовать его для поиска ключа из значения.
lookup = {value: key for key, value in self.data} lookup[value]
рассмотрите возможность использования панд. Как сказано в "Python для анализа данных" Уильяма Маккинни
другой способ думать о серии - это фиксированная длина, упорядоченная dict, поскольку это сопоставление значений индекса со значениями данных. Это может быть используется во многих контекстах, где вы можете использовать дикт.
import pandas as pd list = {'george':16,'amber':19} lookup_list = pd.Series(list)
для запроса серии выполните следующие действия:
lookup_list[lookup_list.values == 19]
что дает:
Out[1]: amber 19 dtype: int64
Если вам нужно сделать что-нибудь еще с выходных преобразование ответ в список может быть полезен:
answer = lookup_list[lookup_list.values == 19].index answer = pd.Index.tolist(answer)
здесь recover_key принимает словарь и значение, чтобы найти в словаре. Затем мы перебираем ключи в словаре и делаем сравнение с тем, что имеет значение, и возвращаем этот конкретный ключ.
def recover_key(dicty,value): for a_key in dicty.keys(): if (dicty[a_key] == value): return a_key
for name in mydict.keys(): if mydict[name] == search_age: print name #or do something else with it. #if in a function append to a temporary list, #then after the loop return the list
это ответ, но это может быть сделано с помощью фантазии "map / reduce", например:
def find_key(value, dictionary): return reduce(lambda x, y: x if x is not None else y, map(lambda x: x[0] if x[1] == value else None, dictionary.iteritems()))
вот мой взгляд на это. Это хорошо для отображения нескольких результатов только в том случае, если вам нужен один. Так что я добавил список, а также
myList = {'george':16,'amber':19, 'rachel':19, 'david':15 } #Setting the dictionary result=[] #Making ready of the result list search_age = int(input('Enter age ')) for keywords in myList.keys(): if myList[keywords] ==search_age: result.append(keywords) #This part, we are making list of results for res in result: #We are now printing the results print(res)
и это все...
нет простого способа найти ключ в списке, "глядя вверх" значение. Однако, если вы знаете значение, повторяя ключи, вы можете искать значения в словаре по элементу. Если D [элемент], где D-объект словаря, равен ключу, который вы пытаетесь найти, вы можете выполнить некоторый код.
D = {'Ali': 20, 'Marina': 12, 'George':16} age = int(input('enter age:\t')) for element in D.keys(): if D[element] == age: print(element)
Я знаю, что это старый, но вы можете довольно легко найти всех людей в списке с вашим возрастом поиска, используя понимание списка.
ages = {'george':16,'amber':19} search = 16 print([name for (name, age) in ages.items() if age == search])
Я нашел это ответ очень эффективный, но все еще не очень легко читать для меня.
чтобы сделать его более ясным можно инвертировать ключ и значение из словаря. Это делает значения ключей и ключи значений, как видно здесь.
mydict = {'george':16,'amber':19} res = dict((v,k) for k,v in mydict.iteritems()) print(res[16]) # Prints george
или
mydict = {'george':16,'amber':19} dict((v,k) for k,v in mydict.iteritems())[16]
что по сути то же, что этот другой ответ.
попробуйте этот однострочный перевернуть словарь:
reversed_dictionary = dict(map(reversed, dictionary.items()))
Cat Plus Plus упомянул, что это не то, как словарь предназначен для использования. Вот почему:
определение словаря аналогично определению отображения в математике. В этом случае dict - это отображение K (набора ключей) в V (значения), но не наоборот. Если вы разыменуете dict, вы ожидаете получить ровно одно возвращенное значение. Но совершенно законно для разных ключей сопоставлять одно и то же значение, например:
d = { k1 : v1, k2 : v2, k3 : v1}
когда вы смотрите вверх a ключ по его соответствующему значению, вы по существу инвертируете словарь. Но отображение не обязательно обратимо! В этом примере запрос ключа, соответствующего v1, может привести к k1 или k3. Вы должны вернуть оба? Только первый найденный? Вот почему indexof () не определен для словарей.
Если вы знаете свои данные, вы можете сделать это. Но API не может предположить, что произвольный словарь обратим, следовательно, отсутствие такой операции.
иногда может потребоваться int ():
titleDic = {'Фильмы':1, 'Музыка':2} def categoryTitleForNumber(self, num): search_title = '' for title, titleNum in self.titleDic.items(): if int(titleNum) == int(num): search_title = title return search_title
вам нужно использовать словарь и обратный этого словаря. Значит вам нужна другая структура данных. Если вы находитесь в Python 3, Используйте
enum
модуль но если вы используете python 2.7 используйтеenum34
обратно портирована в Python 2.пример:
from enum import Enum class Color(Enum): red = 1 green = 2 blue = 3 >>> print(Color.red) Color.red >>> print(repr(Color.red)) <color.red: 1=""> >>> type(Color.red) <enum 'color'=""> >>> isinstance(Color.green, Color) True >>> member = Color.red >>> member.name 'red' >>> member.value 1
уже ответили, но так как несколько человек упомянули реверсирование словаря, вот как вы это делаете в одной строке (предполагая отображение 1:1) и некоторые различные данные perf:
python 2.6:
reversedict = dict([(value, key) for key, value in mydict.iteritems()])
2.7+:
reversedict = {value:key for key, value in mydict.iteritems()}
если вы думаете, что это не 1:1, вы все равно можете создать разумное обратное сопоставление с парой строк:
reversedict = defaultdict(list) [reversedict[value].append(key) for key, value in mydict.iteritems()]
как медленно это: медленнее, чем простой поиск, но и не так медленно, как вы думаете - на 'прямой' 100000 entry dictionary, "быстрый" поиск (т. е. поиск значения, которое должно быть в начале ключей) был примерно в 10 раз быстрее, чем реверсирование всего словаря, а "медленный" поиск (ближе к концу) примерно в 4-5 раз быстрее. Так что после максимум около 10 поисков, он заплатил за себя.
вторая версия (со списками на элемент) занимает около 2,5 х до тех пор, как простая версия.
largedict = dict((x,x) for x in range(100000)) # Should be slow, has to search 90000 entries before it finds it In [26]: %timeit largedict.keys()[largedict.values().index(90000)] 100 loops, best of 3: 4.81 ms per loop # Should be fast, has to only search 9 entries to find it. In [27]: %timeit largedict.keys()[largedict.values().index(9)] 100 loops, best of 3: 2.94 ms per loop # How about using iterkeys() instead of keys()? # These are faster, because you don't have to create the entire keys array. # You DO have to create the entire values array - more on that later. In [31]: %timeit islice(largedict.iterkeys(), largedict.values().index(90000)) 100 loops, best of 3: 3.38 ms per loop In [32]: %timeit islice(largedict.iterkeys(), largedict.values().index(9)) 1000 loops, best of 3: 1.48 ms per loop In [24]: %timeit reversedict = dict([(value, key) for key, value in largedict.iteritems()]) 10 loops, best of 3: 22.9 ms per loop In [23]: %%timeit ....: reversedict = defaultdict(list) ....: [reversedict[value].append(key) for key, value in largedict.iteritems()] ....: 10 loops, best of 3: 53.6 ms per loop
также были некоторые интересные результаты с экспертом. Теоретически, фильтра должен быть быстрее, в этом мы можем использовать itervalues () и, возможно, не нужно создавать/проходить через весь список значений. На практике, результаты были... странный...
In [72]: %%timeit ....: myf = ifilter(lambda x: x[1] == 90000, largedict.iteritems()) ....: myf.next()[0] ....: 100 loops, best of 3: 15.1 ms per loop In [73]: %%timeit ....: myf = ifilter(lambda x: x[1] == 9, largedict.iteritems()) ....: myf.next()[0] ....: 100000 loops, best of 3: 2.36 us per loop
таким образом, для небольших смещений он был значительно быстрее, чем любая предыдущая версия (2.36 *u*S против минимум 1.48 *m*S для предыдущих случаев). Однако, для больших смещений ближе к концу списка, он был значительно медленнее (15.1 МС и ту же 1.48 МС). Небольшая экономия на низком конце не стоит затрат на высоком конце, имхо.
d= {'george':16,'amber':19} dict((v,k) for k,v in d.items()).get(16)
вывод выглядит следующим образом:
-> prints george
вот как вы получаете доступ к словарю, чтобы делать то, что вы хотите:
list = {'george': 16, 'amber': 19} search_age = raw_input("Provide age") for age in list: if list[age] == search_age: print age
конечно, ваши имена настолько выключены, что похоже, что он будет печатать возраст, но он печатает имя. Поскольку вы обращаетесь по имени, это становится более понятным, если вы пишете:
list = {'george': 16, 'amber': 19} search_age = raw_input("Provide age") for name in list: if list[name] == search_age: print name
еще лучше:
people = {'george': {'age': 16}, 'amber': {'age': 19}} search_age = raw_input("Provide age") for name in people: if people[name]['age'] == search_age: print name
вот решение, которое работает как в Python 2, так и в Python 3:
dict((v, k) for k, v in list.items())[search_age]
части до
[search_age]
создает обратный словарь (где значения ключей и наоборот). Вы можете создать вспомогательный метод, который будет кэшировать этот обратный словарь следующим образом:def find_name(age, _rev_lookup=dict((v, k) for k, v in ages_by_name.items())): return _rev_lookup[age]
или даже в более общем случае фабрика, которая создаст метод поиска по возрасту для одного или нескольких из вас lists
def create_name_finder(ages_by_name): names_by_age = dict((v, k) for k, v in ages_by_name.items()) def find_name(age): return names_by_age[age]
так что вы могли бы делать:
find_teen_by_age = create_name_finder({'george':16,'amber':19}) ... find_teen_by_age(search_age)
обратите внимание, что я переименовал
list
доages_by_name
так как первый является предопределенным типом.
dictionary = {'george' : 16, 'amber' : 19} search_age = raw_input("Provide age") key = [filter( lambda x: dictionary[x] == k , dictionary ),[None]][0] # key = None from [None] which is a safeguard for not found.
для нескольких случаев применения:
keys = [filter( lambda x: dictionary[x] == k , dictionary )]