get Key by value, dict, python
Question:
How can I get a key from a value?
my dict:
countries = {
"Normal UK project" : "1",
"UK Omnibus project" : "1-Omni",
"Nordic project" : ["11","12","13","14"],
"German project" : "21",
"French project" : "31"
}
my semi functioning code:
for k, v in countries.items():
if "1" in v:
print k
expected output:
Normal UK project
actual output:
French project
UK Omnibus project
German project
Normal UK project
How can I fix my code?
Answers:
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"
If you want me to shorten it a little bit, I might do
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"
The problem is that the types of the values in the dictionary are not the same, making it much more difficult to use the dictionary, not only in this scenario. While Python allows this, you really should consider unifying the types in the dictionary, e.g. make them all lists. You can do so in just one line of code:
countries = {key: val if isinstance(val, list) else [val]
for key, val in countries.items()}
Now, each single string is wrapped into a list and your existing code will work correctly.
Alternatively, if you have to use the dictionary in it’s current form, you can adapt your lookup function:
for k, v in countries.items():
if "1" == v or isinstance(v, list) and "1" in v:
print k
Your semi-functioning code is returning the other values because with entries like:
"Normal UK project" : "1",
..then "1" in v
checks if the string contains the “1” character, whereas with entries like:
"Nordic project" : ["11","12","13","14"],
..then it will check if the list contains an element “1”.
The in
operator works on both strings and lists, but in a different manner:
>>> "1" in "123"
True
>>> "1" in ["123", "blah"]
False
>>> "1" in ["1", "blah"]
True
Ideally your data would be more consistent – all lists, or all strings:
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
I personally think using in
and the function values
is easier.
print 1 in {1:"123", 2:"blah"}
print "blah" in {1:"123", 2:"blah"}.values()
Output is:
True
True
c={}
– any dict
a(value) – need know this key
key=list(c.keys())[list(c.values()).index(a)]
def get_Value(dic,value):
for name in dic:
if dic[name] == value:
return name
The following code provide another and short version of getting dictionary keys by some value, by using list comprehensions and dic.items():
keys_have_value = [k for k,v in dic.items() if v=="1"]
How can I get a key from a value?
my dict:
countries = {
"Normal UK project" : "1",
"UK Omnibus project" : "1-Omni",
"Nordic project" : ["11","12","13","14"],
"German project" : "21",
"French project" : "31"
}
my semi functioning code:
for k, v in countries.items():
if "1" in v:
print k
expected output:
Normal UK project
actual output:
French project
UK Omnibus project
German project
Normal UK project
How can I fix my code?
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"
If you want me to shorten it a little bit, I might do
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"
The problem is that the types of the values in the dictionary are not the same, making it much more difficult to use the dictionary, not only in this scenario. While Python allows this, you really should consider unifying the types in the dictionary, e.g. make them all lists. You can do so in just one line of code:
countries = {key: val if isinstance(val, list) else [val]
for key, val in countries.items()}
Now, each single string is wrapped into a list and your existing code will work correctly.
Alternatively, if you have to use the dictionary in it’s current form, you can adapt your lookup function:
for k, v in countries.items():
if "1" == v or isinstance(v, list) and "1" in v:
print k
Your semi-functioning code is returning the other values because with entries like:
"Normal UK project" : "1",
..then "1" in v
checks if the string contains the “1” character, whereas with entries like:
"Nordic project" : ["11","12","13","14"],
..then it will check if the list contains an element “1”.
The in
operator works on both strings and lists, but in a different manner:
>>> "1" in "123"
True
>>> "1" in ["123", "blah"]
False
>>> "1" in ["1", "blah"]
True
Ideally your data would be more consistent – all lists, or all strings:
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
I personally think using in
and the function values
is easier.
print 1 in {1:"123", 2:"blah"}
print "blah" in {1:"123", 2:"blah"}.values()
Output is:
True
True
c={}
– any dict
a(value) – need know this key
key=list(c.keys())[list(c.values()).index(a)]
def get_Value(dic,value):
for name in dic:
if dic[name] == value:
return name
The following code provide another and short version of getting dictionary keys by some value, by using list comprehensions and dic.items():
keys_have_value = [k for k,v in dic.items() if v=="1"]