user998316
user998316

Reputation: 10793

Get key by value in dictionary

I made a function which will look up ages in a Dictionary and show the matching name:

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

I know how to compare and find the age I just don't know how to show the name of the person. Additionally, I am getting a KeyError because of line 5. I know it's not correct but I can't figure out how to make it search backwards.

Upvotes: 987

Views: 2713069

Answers (30)

Andrew Anderson
Andrew Anderson

Reputation: 1126

I was looking for this same question and I ended up with my variant:

found_key = [a[0] for a in dict.items() if a[1] == 'value'][0]

Only for those situations when a key has a unique value (which was my case).

Upvotes: 1

AD - Stop Putin -
AD - Stop Putin -

Reputation: 305

As someone mentioned there might be more than one key that have the same value, like my_dict below. Moreover, there might be no matching key.

my_dict ={'k1':1,'k2':2, 'k3':1, 'k4':12, 'k5':1, 'k6':1, 'k7':12}

Here are three ways of finding a key, one for the last hit, and two for the first.

def find_last(search_value:int, d:dict):
    
    return [x for x,y in d.items() if y==search_value].pop()

def find_first1(search_value:int, d:dict):
    return next(filter(lambda x: d[x]==search_value, d.keys()), None)

def find_first2(search_value:int, d:dict):
    return next(x for x,y in  d.items() if y==search_value)

Of these find_first1 is a bit faster than the others, and will return None in case there is no matching key.

Upvotes: 4

rmd0001
rmd0001

Reputation: 183

One line solution using list comprehension, which returns multiple keys if the value is possibly present multiple times.

[key for key,value in mydict.items() if value == 16]

Upvotes: 11

Khaled Eid
Khaled Eid

Reputation: 84

dict_a = {'length': 5, 'width': 9, 'height': 4}

# get the key of specific value 5
key_of_value = list(dict_a)[list(dict_a.values()).index(5)]
print(key_of_value)  # length

# get the key of minimum value
key_min_value = list(dict_a)[list(dict_a.values()).index(sorted(dict_a.values())[0])]
print(key_min_value)  # height

# get the key of maximum value
key_max_value = list(dict_a)[list(dict_a.values()).index(sorted(dict_a.values(), reverse=True)[0])]
print(key_max_value)  # width


Upvotes: 1

Rafael Valero
Rafael Valero

Reputation: 2816

I found this answer very effective but not very easy to read for me.

To make it more clear you can invert the key and the value of a dictionary. This is make the keys values and the values keys, as seen here.

mydict = {'george':16,'amber':19}
res = dict((v,k) for k,v in mydict.iteritems())
print(res[16]) # Prints george

or for Python 3, (thanks @kkgarg)

mydict = {'george':16,'amber':19}
res = dict((v,k) for k,v in mydict.items())
print(res[16]) # Prints george

Also

print(res.get(16)) # Prints george

which is essentially the same that this other answer.

Upvotes: 48

Patrick
Patrick

Reputation: 2977

I thought it would be interesting to point out which methods are the quickest, and in what scenario:

Here's some tests I ran (on a 2012 MacBook Pro)

def method1(dict, search_age):
    for name, age in dict.iteritems():
        if age == search_age:
            return name

def method2(dict, search_age):
    return [name for name,age in dict.iteritems() if age == search_age]

def method3(dict, search_age):
    return dict.keys()[dict.values().index(search_age)]

Results from profile.run() on each method 100,000 times:

Method 1:

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

Method 2:

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

Method 3:

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

So this shows that for a small dict, method 1 is the quickest. This is most likely because it returns the first match, as opposed to all of the matches like method 2 (see note below).


Interestingly, performing the same tests on a dict I have with 2700 entries, I get quite different results (this time run 10,000 times):

Method 1:

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

Method 2:

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

Method 3:

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

So here, method 3 is much faster. Just goes to show the size of your dict will affect which method you choose.

Notes:

  • Method 2 returns a list of all names, whereas methods 1 and 3 return only the first match.
  • I have not considered memory usage. I'm not sure if method 3 creates 2 extra lists (keys() and values()) and stores them in memory.

Upvotes: 130

John
John

Reputation: 1004

This is kind of a strange question because the very first comment provides a perfect answer.
Based on the sample data example provided

dictionary = {'george': 16, 'amber': 19}
print(dictionary["george"])

It returns

16

So you want the opposite
to enter "16" and get "george" So simply swap keys,values and presto

dictionary = {'george': 16, 'amber': 19}
inv_dict = {value:key for key, value in dictionary.items()}
print(inv_dict[16])

I was in the completely opposite position as i had a dictionary like

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

and i was trying to feed "george" and get 16...i tried several kind of loops and iterators that OK..they work but it wasn't the easy one line solution that i would use for quick result...so i simply swapped and solution found.
If i missed something please let me know to delete my answer.

Upvotes: 4

bravhek
bravhek

Reputation: 165

Heres a truly "Reversible Dictionary", Based upon Adam Acosta's solution, but enforcing val-to-key calls to be unique and easily return key from value:

from collections import UserDict


class ReversibleDict(UserDict):
    def __init__(self, enforce_unique=True, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.val_to_keys = {}
        self.check_val = self.check_unique if enforce_unique else lambda x: x

    def __setitem__(self, key, value):
        self.check_val(value)
        super().__setitem__(key, value)
        self.val_to_keys[value] = key

    def __call__(self, value):
        return self.val_to_keys[value]

    def check_unique(self, value):
        assert value not in self.val_to_keys, f"Non unique value '{value}'"
        return value

If you want to enforce uniqueness on dictionary values ensure to set enforce_unique=True. to get keys from values just do rev_dict(value), to call values from keys just do as usual dict['key'], here's an example of usage:

rev_dict = ReversibleDict(enforce_unique=True)
rev_dict["a"] = 1
rev_dict["b"] = 2
rev_dict["c"] = 3
print("full dictinoary is: ", rev_dict)
print("value for key 'b' is: ", rev_dict["b"])
print("key for value '2' is: ", rev_dict(2))
print("tring to set another key with the same value results in error: ")
rev_dict["d"] = 1

Upvotes: 1

Frank Wang
Frank Wang

Reputation: 431

I glimpsed all answers and none mentioned simply using list comprehension?

This Pythonic one-line solution can return all keys for any number of given values (tested in Python 3.9.1):

>>> dictionary = {'george' : 16, 'amber' : 19, 'frank': 19}
>>>
>>> age = 19
>>> name = [k for k in dictionary.keys() if dictionary[k] == age]; name
['george', 'frank']
>>>
>>> age = (16, 19)
>>> name = [k for k in dictionary.keys() if dictionary[k] in age]; name
['george', 'amber', 'frank']
>>>
>>> age = (22, 25)
>>> name = [k for k in dictionary.keys() if dictionary[k] in age]; name
[]

Upvotes: 5

Adam Acosta
Adam Acosta

Reputation: 603

I realize it's been a long time and the original asker likely no longer has any need of an answer, but none of these are good answers if you actually have control over this code. You're just using the wrong data structure. This is a perfect illustration of the use case for a two-way dict:

>>> from collections import defaultdict, UserDict
>>> class TwoWayDict(UserDict):
...     def __init__(self, *args, **kwargs):
...         super().__init__(*args, **kwargs)
...         self.val_to_keys = defaultdict(list)
...     def __setitem__(self, key, value):
...         super().__setitem__(key, value)
...         self.val_to_keys[value].append(key)
...     def get_keys_for_val(self, value):
...         return self.val_to_keys[value]
... 
>>> d = TwoWayDict()
>>> d['a'] = 1
>>> d['b'] = 1
>>> d.get_keys_for_val(1)
['a', 'b']

Adds miniscule overhead to insertions but you keep constant-time lookup, except now in both directions. No need to construct the reverse mapping from scratch every time you need it. Just store it as you go and access it as needed.

Further, many of these answers are not even correct because clearly many people can have the same age but they're only returning the first matching key, not all of them.

Upvotes: 1

pgalilea
pgalilea

Reputation: 267

I ended up doing it with a function. This way you might avoid doing the full loop, and the intuition says that it should be faster than other solutions presented.

def get_key_from_value(my_dict, to_find):

    for k,v in my_dict.items():
        if v==to_find: return k

    return None

Upvotes: 0

Carson
Carson

Reputation: 8098

my_dict = {'A': 19, 'B': 28, 'carson': 28}
search_age = 28

take only one

name = next((name for name, age in my_dict.items() if age == search_age), None)
print(name)  # 'B'

get multiple data

name_list = [name for name, age in filter(lambda item: item[1] == search_age, my_dict.items())]
print(name_list)  # ['B', 'carson']

Upvotes: 7

fanny
fanny

Reputation: 1441

one line version: (i is an old dictionary, p is a reversed dictionary)

explanation : i.keys() and i.values() returns two lists with keys and values of the dictionary respectively. The zip function has the ability to tie together lists to produce a dictionary.

p = dict(zip(i.values(),i.keys()))

Warning : This will work only if the values are hashable and unique.

Upvotes: 89

faham
faham

Reputation: 892

key = next((k for k in my_dict if my_dict[k] == val), None)

Upvotes: 37

Cat Plus Plus
Cat Plus Plus

Reputation: 129934

There is none. dict is not intended to be used this way.

dictionary = {'george': 16, 'amber': 19}
search_age = input("Provide age")
for name, age in dictionary.items():  # for name, age in dictionary.iteritems():  (for Python 2.x)
    if age == search_age:
        print(name)

Upvotes: 701

Stênio Elson
Stênio Elson

Reputation: 10083

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

Or in Python 3.x:

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

Basically, it separates the dictionary's values in a list, finds the position of the value you have, and gets the key at that position.

More about keys() and .values() in Python 3: How can I get list of values from dict?

Upvotes: 1005

Sakhri Houssem
Sakhri Houssem

Reputation: 1063

we can get the Key of dict by :

def getKey(dct,value):
     return [key for key in dct if (dct[key] == value)]

Upvotes: 15

patrick
patrick

Reputation: 61

for name in mydict:
    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

Upvotes: 6

Mansur Ul Hasan
Mansur Ul Hasan

Reputation: 3606

In my case the easiest way is to instantiate disctionary in your code then you can call keys from it like below

here is my class having dictionary

class Config:

def local(self):
    return {
        "temp_dir": "/tmp/dirtest/",
        "devops": "Mansur",
    }

To instantiate your dictionary

config =  vars.Config()
local_config = config.local()

Finally calling your dictionary keys

patched = local_config.get("devops")

Upvotes: 0

Bishwas Mishra
Bishwas Mishra

Reputation: 1342

Just my answer in lambda and filter.

filter( lambda x, dictionary=dictionary, search_age=int(search_age): dictionary[x] == search_age  , dictionary )

Upvotes: 4

Ozkan Serttas
Ozkan Serttas

Reputation: 1017

I tried to read as many solutions as I can to prevent giving duplicate answer. However, if you are working on a dictionary which values are contained in lists and if you want to get keys that have a particular element you could do this:

d = {'Adams': [18, 29, 30],
     'Allen': [9, 27],
     'Anderson': [24, 26],
     'Bailey': [7, 30],
     'Baker': [31, 7, 10, 19],
     'Barnes': [22, 31, 10, 21],
     'Bell': [2, 24, 17, 26]}

Now lets find names that have 24 in their values.

for key in d.keys():    
    if 24 in d[key]:
        print(key)

This would work with multiple values as well.

Upvotes: 4

johnaphun
johnaphun

Reputation: 694

Try this one-liner to reverse a dictionary:

reversed_dictionary = dict(map(reversed, dictionary.items()))

Upvotes: 25

Cesar
Cesar

Reputation: 4437

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.

For multiple occurrences use:

keys = [filter( lambda x: dictionary[x] == k  , dictionary )]

Upvotes: 1

Brett
Brett

Reputation: 541

get_key = lambda v, d: next(k for k in d if d[k] is v)

Upvotes: 11

Shishir
Shishir

Reputation: 189

Here, recover_key takes dictionary and value to find in dictionary. We then loop over the keys in dictionary and make a comparison with that of value and return that particular key.

def recover_key(dicty,value):
    for a_key in dicty.keys():
        if (dicty[a_key] == value):
            return a_key

Upvotes: 7

Axel
Axel

Reputation: 160

Consider using Pandas. As stated in William McKinney's "Python for Data Analysis'

Another way to think about a Series is as a fixed-length, ordered dict, as it is a mapping of index values to data values. It can be used in many contexts where you might use a dict.

import pandas as pd
list = {'george':16,'amber':19}
lookup_list = pd.Series(list)

To query your series do the following:

lookup_list[lookup_list.values == 19]

Which yields:

Out[1]: 
amber    19
dtype: int64

If you need to do anything else with the output transforming the answer into a list might be useful:

answer = lookup_list[lookup_list.values == 19].index
answer = pd.Index.tolist(answer)

Upvotes: 9

Meilin He
Meilin He

Reputation: 69

A simple way to do this could be:

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

This will return a list of the keys with value that match search_age. You can also replace "list==search_age" with any other conditions statement if needed.

Upvotes: 0

Jelen
Jelen

Reputation: 633

a = {'a':1,'b':2,'c':3}
{v:k for k, v in a.items()}[1]

or better

{k:v for k, v in a.items() if v == 1}

Upvotes: 41

Andriy Ivaneyko
Andriy Ivaneyko

Reputation: 22051

You can get key by using dict.keys(), dict.values() and list.index() methods, see code samples below:

names_dict = {'george':16,'amber':19}
search_age = int(raw_input("Provide age"))
key = names_dict.keys()[names_dict.values().index(search_age)]

Upvotes: 12

Raj Damani
Raj Damani

Reputation: 802

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

Upvotes: 3

Related Questions