получить ключ по значению, 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

c={} - любой дикт
a (value) - нужно знать этот ключ

key=list(c.keys())[list(c.values()).index(a)]]

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

def get_Value(dic,value):
    for name in dic:
        if dic[name] == value:
            return name