getting dict key using dict value in python

2019-07-28 04:51发布

问题:

My question is: How can I get a dictionary key using a dictionary value?

d={'dict2': {1: 'one', 2: 'two'}, 'dict1': {3: 'three', 4: 'four'}}

I want to get dict2 the key of the key of two.

Thanks.

回答1:

Here's a recursive solution that can handle arbitrarily nested dictionaries:

>>> import collections
>>> def dict_find_recursive(d, target):
...     if not isinstance(d, collections.Mapping):
...         return d == target
...     else:
...         for k in d:
...             if dict_find_recursive(d[k], target) != False:
...                 return k
...     return False

It's not as efficient in the long run as a "reverse dictionary," but if you aren't doing such reverse searches frequently, it probably doesn't matter. (Note that you have to explicitly compare the result of dict_find_recursive(d[k], target) to False because otherwise falsy keys like '' cause the search to fail. In fact, even this version fails if False is used as a key; a fully general solution would use a unique sentinel object() to indicate falseness.)

A few usage examples:

>>> d = {'dict1': {3: 'three', 4: 'four'}, 'dict2': {1: 'one', 2: 'two'}}
>>> dict_find_recursive(d, 'two')
'dict2'
>>> dict_find_recursive(d, 'five')
False
>>> d = {'dict1': {3: 'three', 4: 'four'}, 'dict2': {1: 'one', 2: 'two'}, 
         'dict3': {1: {1:'five'}, 2: 'six'}}
>>> dict_find_recursive(d, 'five')
'dict3'
>>> dict_find_recursive(d, 'six')
'dict3'

If you want to reverse an arbitrarily nested set of dictionaries, recursive generators are your friend:

>>> def dict_flatten(d):
...     if not isinstance(d, collections.Mapping):
...         yield d
...     else:
...         for value in d:
...             for item in dict_flatten(d[value]):
...                 yield item
... 
>>> list(dict_flatten(d))
['three', 'four', 'five', 'six', 'one', 'two']

The above simply lists all the values in the dictionary that aren't mappings. You can then map each of those values to a key like so:

>>> def reverse_nested_dict(d):
...     for k in d:
...         if not isinstance(d[k], collections.Mapping):
...             yield (d[k], k)
...         else:
...             for item in dict_flatten(d[k]):
...                 yield (item, k)
... 

This generates a iterable of tuples, so no information is lost:

>>> for tup in reverse_nested_dict(d):
...     print tup
... 
('three', 'dict1')
('four', 'dict1')
('five', 'dict3')
('six', 'dict3')
('one', 'dict2')
('two', 'dict2')

If you know that all your non-mapping values are hashable -- and if you know they are unique, or if you don't care about collisions -- then just pass the resulting tuples to dict():

>>> dict(reverse_nested_dict(d))
{'six': 'dict3', 'three': 'dict1', 'two': 'dict2', 'four': 'dict1', 
 'five': 'dict3', 'one': 'dict2'}


回答2:

If you don't want to reverse the dictionary, here's another possible solution:

def get_key_from_value(my_dict, v):
    for key,value in my_dict.items():
        if value == v:
            return key
    return None

>>> d = {1: 'one', 2: 'two'}
>>> get_key_from_value(d,'two')
2


回答3:

The following will create a reverse dictionary for the two-level example:

d={'dict2': {1: 'one', 2: 'two'}, 'dict1': {3: 'three', 4: 'four'}}
r = {}
for d1 in d:
    for d2 in d[d1]:
        r[d[d1][d2]] = d1

The result:

>>> r
{'four': 'dict1', 'three': 'dict1', 'two': 'dict2', 'one': 'dict2'}


回答4:

I don't know about the best solution, but one possibility is reversing the dictionary (so that values becomes keys) and then just doing a normal key lookup. This will reverse a dictionary:

forward_dict = { 'key1': 'val1', 'key2': 'val2'}
reverse_dict = dict([(v,k) for k,v in forward_dict.items()])

So given "val1", I can just do:

reverse_dict["val1"]

to find the corresponding key. There are obvious problems with this solution -- for example, if your values aren't unique, you're going to lose some information.



回答5:

Write code to reverse the dictionary (i.e. create a new dictionary that maps the values of the old one to the keys of the old one).
Since you seem to be dealing with nested dictionaries, this will obviously be trickier. Figure out the least you need to get your problem solved and code that up (i.e. don't create a solution that will work arbitrary depths of nesting if your problem only deals with dicts in dicts which in turn don't have any dicts)



回答6:

To handle the nested dictionaries I would do just as senderle's answer states.

However if in the future it does not contain nested dictionaries, be very careful doing a simple reversal. By design the dictionary keys are unique, but the values do not have this requirement.

If you have values that are the same for multiple keys, when reversing the dictionary you will lose all but one of them. And because dictionaries are not sorted, you could lose different data arbitrarily.

Example of reversal working:

>>> d={'dict1': 1, 'dict2': 2, 'dict3': 3, 'dict4': 4}
>>> rd = dict([(v,k) for k,v in d.items()])
>>> print d
{'dict4': 4, 'dict1': 1, 'dict3': 3, 'dict2': 2}

>>> print rd
{1: 'dict1', 2: 'dict2', 3: 'dict3', 4: 'dict4'}  

Example of reversal failure: Note that dict4 is lost

>>> d={'dict1': 1, 'dict2': 4, 'dict3': 3, 'dict4': 4}
>>> rd = dict([(v,k) for k,v in d.items()])
>>> print d
{'dict4': 4, 'dict1': 1, 'dict3': 3, 'dict2': 4}

>>> print rd
{1: 'dict1', 3: 'dict3', 4: 'dict2'}


回答7:

here's an example nobody thinks about: (could be used similarly)

raw_dict = { 'key1': 'val1', 'key2': 'val2', 'key3': 'val1' }

new_dict = {}
for k,v in raw_dict.items():
    try: new_dict[v].append(k)
    except: new_dict[v] = [k]

result:

>>> new_dict
{'val2': ['key2'], 'val1': ['key3', 'key1']}

maybe not the best of methods, but it works for what I need it for.