940

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.

Neuron
  • 5,141
  • 5
  • 38
  • 59
user998316
  • 10,313
  • 4
  • 18
  • 11

43 Answers43

938
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?

Stênio Elson
  • 9,413
  • 1
  • 12
  • 3
  • 42
    Looks great but is it works always? I mean, do `list.keys()` and `list.values()` functions generate items in same order? – iskorum Sep 23 '13 at 14:01
  • 38
    Yes, they are guaranteed to be consistent. Additionally order is guaranteed not to change through iterations as long as the dictionary is not modified. – Veedrac Sep 25 '13 at 23:21
  • 18
    This looks to be a good solution but index gave only one value right, so if you ve multiple equal values, then it should return multiple keys right ? – James Sapam Dec 13 '13 at 13:17
  • 1
    The keys() may not be ordered as per the values() always – deeshank Nov 17 '14 at 10:09
  • @Veedrac - Do you have any proof to backup your statement? – ArtOfWarfare Aug 06 '15 at 18:04
  • 19
    @ArtOfWarfare https://docs.python.org/3/library/stdtypes.html#dict-views, "If keys, values and items views are iterated over with no intervening modifications to the dictionary, the order of items will directly correspond." – Veedrac Aug 06 '15 at 19:14
  • 1
    @Veedrac - Very nice, thank you. I checked the same section of the documentation and it also applies to 2.7. The promise is still there in 2.6, although phrased slightly differently... it sounds like in 2.6 the promise only applied to CPython, not other Python implementations. – ArtOfWarfare Aug 06 '15 at 19:30
  • 4
    This solution worked nicely for me in an instance where I knew only one key could have the value in question, however, if multiple values exist, it will return one of them. (P 2.6) – DaveL17 Feb 02 '16 at 13:22
  • 7
    @sinekonata: It still performs an expensive loop under the hood; the loop is just hidden inside the `index` method. – user2357112 Apr 27 '16 at 23:47
  • @iskorum yes, it will always work. even I too had same doubt but after reading this - http://stackoverflow.com/questions/15479928/why-is-the-order-in-dictionaries-and-sets-arbitrary everything becomes clear. – Amit Upadhyay Feb 12 '17 at 10:03
  • 1
    It's an elegant way but a question: what if the values are unique but still includes my 'keyword'. imagine a dict with 'order' and 'suborder' values and I'm looking for 'order' by searching in dict.values(). Do I get the relevant key by using ur method or either of them? – JMJ Jun 04 '18 at 21:13
  • It's nice but the other solutions further down are a lot more readable. – pfabri May 13 '20 at 16:43
  • 3
    list(mydict) does the same thing as list(mydict.keys()) – quixote Nov 15 '20 at 18:01
  • 1
    For this to work I need to say `list(mydict.keys())` and `list(mydict.values())`. That aside, this works just fine. Thanks! :-) – Markus-Hermann Mar 07 '23 at 09:18
690

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)
Georgy
  • 12,464
  • 7
  • 65
  • 73
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
  • 124
    I don't agree... agf's answer below is more constructive. A perfectly reasonable use case is not "unintended" (list comprehension fits such a use case anyway). A `dict` can be for multiple things at different times; keys and values have a clear meaning, of course, but _"`dict` items with a given value"_ is a perfectly reasonable request. The recommendation to use a list of pairs would discard the context that one item is a '_definition_' from the other, e.g. in parameter lists... – Louis Maddox Oct 13 '16 at 13:20
  • 10
    I do not agree with this answer. The fact that it is a possibility, as shown in answer by Stênio Elson, does not imply that it was not intended to be used as such. Not helpful at all. – Tropicalrambler Jan 08 '20 at 17:52
  • Would you find a word in a dictionary based on its definition? NOPE. @Tropicalrambler – Jossie Calderon Jun 05 '20 at 00:55
  • Although you have a point that a standard use for a word dictionary is to search the definition of the word with word = key and definition = value, today's programming languages enable you to search by value if necessary. If you are working with a key:value pair object (call it dictionary, tuple, whatever name for whatever language). In python, it's a fact that you can still index through the values of the structure to find out the corresponding keys. – Tropicalrambler Jun 08 '20 at 02:49
  • 6
    @JossieCalderon Yes. I often google the description of what I mean to get the word. This is essentially finding a word in a dictionary according to the definition. – David Jun 17 '20 at 14:24
  • @DavidIreland It's atypical. – Jossie Calderon Jun 17 '20 at 20:11
  • this is the best, imho, since it can handle string values as well and not just integers. – Ulf Gjerdingen May 30 '21 at 09:24
  • 1
    @DavidIreland that only works because Google has made a reverse index of the entire internet. – Mark Ransom Jun 11 '21 at 19:20
  • @MarkRansom not really, I have been giving descriptions of words to my friends so they can give me the word for longer than Google has existed. – David Jun 12 '21 at 13:25
  • This answers shows that it is a possibility, but also adds that if you are trying to access a dictionary by its value, you're probably using the wrong pattern. This answer is richer than that of @Stênio Elson, which is technically not accessing a dictionary anymore. – Eduardo Pignatelli Jun 15 '23 at 08:56
  • For python 3 a readable one liner version of this command is `[k for k,v in dictionary.items() if v == search_age]`. As a bonus it will return all keys matching a value if there are duplicates and it works on unhashable values unlike some of the reversed dictionary answers – Chris Rudd Jul 14 '23 at 22:03
346

If you want both the name and the age, you should be using .items() which gives you key (key, value) tuples:

for name, age in mydict.items():
    if age == search_age:
        print name

You can unpack the tuple into two separate variables right in the for loop, then match the age.

You should also consider reversing the dictionary if you're generally going to be looking up by age, and no two people have the same age:

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

so you can look up the name for an age by just doing

mydict[search_age]

I've been calling it mydict instead of list because list is the name of a built-in type, and you shouldn't use that name for anything else.

You can even get a list of all people with a given age in one line:

[name for name, age in mydict.items() if age == search_age]

or if there is only one person with each age:

next((name for name, age in mydict.items() if age == search_age), None)

which will just give you None if there isn't anyone with that age.

Finally, if the dict is long and you're on Python 2, you should consider using .iteritems() instead of .items() as Cat Plus Plus did in his answer, since it doesn't need to make a copy of the list.

agf
  • 171,228
  • 44
  • 289
  • 238
  • 11
    Correct, but if you're going to do linear search, you might as well replace the `dict` with a list of pairs. – Fred Foo Nov 05 '11 at 21:15
  • 12
    Unless your usual action is looking ages up by name, in which case a `dict` makes sense. – agf Nov 05 '11 at 21:16
  • 7
    It seems peculiar to assume that there is only one person with each age, while on the other hand, it is completely logical for each person to have a single age. – Dannid Feb 09 '16 at 01:30
  • @Dannid Yes, but the problem can be easily generalised. For example you could have a look up table with unique keys and their corresponding unique values. You can then look up things symmetrically `value --> key` or `key --> value` – pfabri May 13 '20 at 16:34
120

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.
Alex C
  • 11
  • 1
  • 3
Patrick
  • 2,769
  • 2
  • 25
  • 29
  • 9
    Just an update: it seems that dict.values() and dict.keys() both return lists that reference the objects from the original dict, so method 3 is also the one that uses the least memory (it only creates two thin list objects which wrap the contents of the dicts, whereas the others create iterator items – Patrick Sep 10 '13 at 04:28
  • 1
    I just wanted to benchmark it myself, scrolled down, bam there you have it. Thanks! Technically as you already pointed out method 2 doesn't do the exact same thing as 1 and 3 because it returns all matches. would be nice to see the results for e.g. return next([..]). – Ramon Jun 23 '15 at 08:33
  • Another important note to make is Python version. I know some versions have more efficient implementations of methods than others. – ArtOfWarfare Aug 06 '15 at 18:05
  • @Patrick: all methods use direct references to the values and keys, there is no memory advantage to any. Except in Python 3 `.keys()` and` `.values()` return dictionary views, which are light-weight. – Martijn Pieters Sep 09 '18 at 13:23
  • 2
    @Martijn @Patrick, Since python 3.6, dict_keys dict_values do not have index attributes anymore, and you need to convert it first to a list, which will be memory hungry I guess (method 3). So it ends up like `list(dict.keys())[list(dict.values()).index(search_age)]` – Orsiris de Jong May 03 '21 at 08:43
  • 5
    @OrsirisdeJong `dict.keys()`, etc are *dictionary view objects* and have been so in all Python 3 releases, not just since 3.6. Don’t turn those into a list, use `next((k for k, v in dict.items() if v == search_age), None)` to find a match. – Martijn Pieters May 05 '21 at 23:19
  • 3
    @MartijnPieters Indeed your solution is way less memory hungry than lists and replaces Method 3 well. Just a thing, you made an error inverting k and v. The correct version should be `next((k for k, v in dict.items() if v == search_age), None)`. Anyway, thanks for the answer ;) – Orsiris de Jong May 06 '21 at 08:06
86

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.

pfabri
  • 885
  • 1
  • 9
  • 25
fanny
  • 1,373
  • 12
  • 25
  • 1
    Yes, this will work: http://stackoverflow.com/questions/835092/python-dictionary-are-keys-and-values-always-the-same-order – The Unfun Cat Oct 25 '13 at 07:52
  • 25
    ... and when there are no duplicate values. – ely May 22 '14 at 19:49
  • 4
    Beautiful. W.r.t the comment above, of course it only works when there are no duplicate values, but then, the question that started this thread makes the assumption that we have a one-to-one function, so given that assumption, this is the most elegant response by far. – John Strong Feb 10 '17 at 17:10
  • 1
    expanding on hashable values: if your values are lists/sets convert them to tuple for this to work (they still need to be unique). – muon Jul 12 '18 at 15:31
47

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.

Rafael Valero
  • 2,736
  • 18
  • 28
40
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}
Jelen
  • 613
  • 5
  • 7
35
key = next((k for k in my_dict if my_dict[k] == val), None)
faham
  • 842
  • 11
  • 17
21

Try this one-liner to reverse a dictionary:

reversed_dictionary = dict(map(reversed, dictionary.items()))
johnaphun
  • 644
  • 6
  • 16
15

If you want to find the key by the value, you can use a dictionary comprehension to create a lookup dictionary and then use that to find the key from the value.

lookup = {value: key for key, value in self.data}
lookup[value]
Safia Abdalla
  • 151
  • 1
  • 4
12

we can get the Key of dict by :

def getKey(dct,value):
     return [key for key in dct if (dct[key] == value)]
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Sakhri Houssem
  • 975
  • 2
  • 16
  • 32
11

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)]
Andriy Ivaneyko
  • 20,639
  • 6
  • 60
  • 82
10

Here is my take on this problem. :) I have just started learning Python, so I call this:

"The Understandable for beginners" solution.

#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!
10
get_key = lambda v, d: next(k for k in d if d[k] is v)
Brett
  • 491
  • 4
  • 9
  • Nice one-liner. However, `is` should be used only for equality testing of singletons (`None`, `True`, `False` etc.). The fact that CPython reuses string literals (and therefore `a = 'foobar'; a is 'foobar'` is `True`) is an implementation detail and should not be relied on. – piit79 Nov 18 '19 at 11:42
  • 1
    And one more comment: `get_key` will throw `StopIteration` if the value doesn't exist in the dictionary - it would be better to use `next(..., None)` which would return `None` if the value wasn't found. – piit79 Nov 18 '19 at 12:00
  • A slight modification will work if the dictionary doesn't contains single elements but sets: `get_first_key = lambda v, d: next((k for k in d if (v in d[k] is not None)), None)` – supernova May 05 '20 at 16:59
8

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)
Axel
  • 150
  • 2
  • 7
6
d= {'george':16,'amber':19}

dict((v,k) for k,v in d.items()).get(16)

The output is as follows:

-> prints george
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
Jeroen
  • 69
  • 1
  • 1
6

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
Shishir
  • 169
  • 2
  • 6
6

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]
tbjorch
  • 1,544
  • 1
  • 8
  • 21
rmd0001
  • 133
  • 1
  • 5
5
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
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
patrick
  • 51
  • 1
  • 1
5
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']
Carson
  • 6,105
  • 2
  • 37
  • 45
5

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
[]
Frank Wang
  • 381
  • 3
  • 7
4

it's answered, but it could be done with a fancy 'map/reduce' use, e.g.:

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()))
formiaczek
  • 385
  • 3
  • 7
4

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.

Ozkan Serttas
  • 947
  • 13
  • 14
4

Just my answer in lambda and filter.

filter( lambda x, dictionary=dictionary, search_age=int(search_age): dictionary[x] == search_age  , dictionary )
Bishwas Mishra
  • 1,235
  • 1
  • 12
  • 25
3

already been answered, but since several people mentioned reversing the dictionary, here's how you do it in one line (assuming 1:1 mapping) and some various perf data:

python 2.6:

reversedict = dict([(value, key) for key, value in mydict.iteritems()])

2.7+:

reversedict = {value:key for key, value in mydict.iteritems()}

if you think it's not 1:1, you can still create a reasonable reverse mapping with a couple lines:

reversedict = defaultdict(list)
[reversedict[value].append(key) for key, value in mydict.iteritems()]

how slow is this: slower than a simple search, but not nearly as slow as you'd think - on a 'straight' 100000 entry dictionary, a 'fast' search (i.e. looking for a value that should be early in the keys) was about 10x faster than reversing the entire dictionary, and a 'slow' search (towards the end) about 4-5x faster. So after at most about 10 lookups, it's paid for itself.

the second version (with lists per item) takes about 2.5x as long as the simple version.

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

Also had some interesting results with ifilter. Theoretically, ifilter should be faster, in that we can use itervalues() and possibly not have to create/go through the entire values list. In practice, the results were... odd...

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

So, for small offsets, it was dramatically faster than any previous version (2.36 *u*S vs. a minimum of 1.48 *m*S for previous cases). However, for large offsets near the end of the list, it was dramatically slower (15.1ms vs. the same 1.48mS). The small savings at the low end is not worth the cost at the high end, imho.

Corley Brigman
  • 11,633
  • 5
  • 33
  • 40
  • I so much want this (reversedict = defaultdict(list) reversedict[value].append(key) for key, value in largedict.iteritems()] ) to work, but using Python 2.7.3, I get syntax error on the word 'for' – slashdottir Jan 23 '14 at 22:53
  • is that what you actually typed? you're missing a `[` in it, if it is. otherwise, make sure it's on two lines, or put a `;` between them if it's not. – Corley Brigman Jan 23 '14 at 23:37
3

Cat Plus Plus mentioned that this isn't how a dictionary is intended to be used. Here's why:

The definition of a dictionary is analogous to that of a mapping in mathematics. In this case, a dict is a mapping of K (the set of keys) to V (the values) - but not vice versa. If you dereference a dict, you expect to get exactly one value returned. But, it is perfectly legal for different keys to map onto the same value, e.g.:

d = { k1 : v1, k2 : v2, k3 : v1}

When you look up a key by it's corresponding value, you're essentially inverting the dictionary. But a mapping isn't necessarily invertible! In this example, asking for the key corresponding to v1 could yield k1 or k3. Should you return both? Just the first one found? That's why indexof() is undefined for dictionaries.

If you know your data, you could do this. But an API can't assume that an arbitrary dictionary is invertible, hence the lack of such an operation.

Dan Ahlquist
  • 161
  • 1
  • 6
3

here is my take on it. This is good for displaying multiple results just in case you need one. So I added the list as well

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)

And that's it...

3

There is no easy way to find a key in a list by 'looking up' the value. However, if you know the value, iterating through the keys, you can look up values in the dictionary by the element. If D[element] where D is a dictionary object, is equal to the key you're trying to look up, you can execute some code.

D = {'Ali': 20, 'Marina': 12, 'George':16}
age = int(input('enter age:\t'))  
for element in D.keys():
    if D[element] == age:
        print(element)
TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
Ethan
  • 65
  • 7
3

You need to use a dictionary and reverse of that dictionary. It means you need another data structure. If you are in python 3, use enum module but if you are using python 2.7 use enum34 which is back ported for python 2.

Example:

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 
hamidfzm
  • 4,595
  • 8
  • 48
  • 80
3
def get_Value(dic,value):
    for name in dic:
        if dic[name] == value:
            del dic[name]
            return name
Raj Damani
  • 782
  • 1
  • 6
  • 19
3

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.

DannyDannyDanny
  • 838
  • 9
  • 26
John
  • 974
  • 8
  • 16
  • 5
    Hi, inverse dict is a good solution but you have to keep in mind there mustn't be duplicate values in your dictionary, otherwise you would lose some values in in the inverted dict. How to tackle that was answered for example here in the answer by Robert Rossney https://stackoverflow.com/questions/483666/reverse-invert-a-dictionary-mapping. – DovaX Mar 12 '21 at 23:51
  • This is a good possibility but at least for my case i don't have duplicates – John Mar 13 '21 at 19:07
  • that's bad solution if there's a duplicated values – urek mazino May 10 '22 at 13:30
3

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.

2

Sometimes int() may be needed:

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
Denis Kutlubaev
  • 15,320
  • 6
  • 84
  • 70
2

This is how you access the dictionary to do what you want:

list = {'george': 16, 'amber': 19}
search_age = raw_input("Provide age")
for age in list:
    if list[age] == search_age:
        print age

of course, your names are so off it looks like it would be printing an age, but it DOES print the name. Since you are accessing by name, it becomes more understandable if you write:

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

Better yet:

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
1

Here is a solution which works both in Python 2 and Python 3:

dict((v, k) for k, v in list.items())[search_age]

The part until [search_age] constructs the reverse dictionary (where values are keys and vice-versa). You could create a helper method which will cache this reversed dictionary like so:

def find_name(age, _rev_lookup=dict((v, k) for k, v in ages_by_name.items())):
    return _rev_lookup[age]

or even more generally a factory which would create a by-age name lookup method for one or more of you 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]

so you would be able to do:

find_teen_by_age = create_name_finder({'george':16,'amber':19})
...
find_teen_by_age(search_age)

Note that I renamed list to ages_by_name since the former is a predefined type.

eold
  • 5,972
  • 11
  • 56
  • 75
1
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 )]
Cesar
  • 4,418
  • 2
  • 31
  • 37
1

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.

Adam Acosta
  • 603
  • 3
  • 6
1

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
bravhek
  • 155
  • 5
1
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


Khaled Eid
  • 54
  • 5
0

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.

Meilin He
  • 69
  • 1
  • 3
0

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")
Mansur Ul Hasan
  • 2,898
  • 27
  • 24
0

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
pgalilea
  • 261
  • 2
  • 5
0

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).

Andrew Anderson
  • 1,044
  • 3
  • 17
  • 26