получить ключ по значению, dict, python
как я могу получить ключ от значения?
мой дикт:
countries = {
"Normal UK project" : "1",
"UK Omnibus project" : "1-Omni",
"Nordic project" : ["11","12","13","14"],
"German project" : "21",
"French project" : "31"
}
мой полу функционирующий код:
for k, v in countries.items():
if "1" in v:
print k
ожидаемый результат:
Normal UK project
фактический выход:
French project
UK Omnibus project
German project
Normal UK project
как я могу исправить мой код?
7 ответов
проблема в том, что типы значений в словаре не совпадают, что значительно затрудняет использование словаря, не только в этом сценарии. Хотя Python позволяет это, вы действительно должны рассмотреть возможность объединения типов в словаре, например, сделать их все списки. Вы можете сделать это в одну строку кода:
countries = {key: val if isinstance(val, list) else [val]
for key, val in countries.items()}
теперь каждая строка завернута в список, и ваш существующий код будет работать правильно.
альтернативно, если вам нужно использовать словарь в его текущей форме, вы можете адаптировать свою функцию поиска:
for k, v in countries.items():
if "1" == v or isinstance(v, list) and "1" in v:
print k
def keys_of_value(dct, value):
for k in dct:
if isinstance(dct[k], list):
if value in dct[k]:
return k
else:
if value == dct[k]:
return k
assert keys_of_value(countries, "12") == "Nordic project"
assert keys_of_value(countries, "1") == "Normal UK project"
Если вы хотите, чтобы я сократил его немного, я мог бы сделать
from operator import eq, contains
def keys_of_value(dct, value, ops = (eq, contains)):
for k in dct:
if ops[isinstance(dct[k], list)](dct[k], value):
return k
assert keys_of_value(countries, "12") == "Nordic project"
assert keys_of_value(countries, "1") == "Normal UK project"
следующий код предоставляет другую и короткую версию получения ключей словаря по некоторому значению, используя list comprehensions и dic.items ():
keys_have_value = [k for k,v in dic.items() if v=="1"]
ваш полуфункциональный код возвращает другие значения, потому что с такими записями, как:
"Normal UK project" : "1",
..тогда "1" in v
проверяет, содержит ли строка символ "1", тогда как с такими записями, как:
"Nordic project" : ["11","12","13","14"],
..затем он проверит, содержит ли список элемент "1".
на in
оператор работает как со строками, так и со списками, но по-разному:
>>> "1" in "123"
True
>>> "1" in ["123", "blah"]
False
>>> "1" in ["1", "blah"]
True
В идеале ваши данные будут более согласованными-все списки или все строки:
countries = {
"Normal UK project" : ["1"],
"UK Omnibus project" : ["1-Omni"],
"Nordic project" : ["11","12","13","14"],
"German project" : ["21"],
"French project" : ["31"]
}
for k, v in countries.items():
if "1" in v:
print k
Я лично думаю, что с помощью in
и - это легче.
print 1 in {1:"123", 2:"blah"}
print "blah" in {1:"123", 2:"blah"}.values()
вывод:
True
True