getting dict key using dict value in python - python

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.

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'}

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

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'}

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.

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)

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'}

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.

Related

How to loop nested dictionary ? [Python] [duplicate]

I have a nested python dictionary data structure. I want to read its keys and values without using collection module. The data structure is like bellow.
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
I was trying to read the keys in the dictionary using the bellow way but getting error.
Code
for key, value in d:
print(Key)
Error
ValueError: too many values to unpack (expected 2)
So can anyone please explain the reason behind the error and how to iterate through the dictionary.
keys() method returns a view object that displays a list of all the keys in the dictionary
Iterate nested dictionary:
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
for i in d.keys():
print i
for j in d[i].keys():
print j
OR
for i in d:
print i
for j in d[i]:
print j
output:
dict1
foo
bar
dict2
baz
quux
where i iterate main dictionary key and j iterate the nested dictionary key.
The following will work with multiple levels of nested-dictionary:
def get_all_keys(d):
for key, value in d.items():
yield key
if isinstance(value, dict):
yield from get_all_keys(value)
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'dict3': {'baz': 3, 'quux': 4}}}
for x in get_all_keys(d):
print(x)
This will give you:
dict1
foo
bar
dict2
dict3
baz
quux
As the requested output, the code goes like this
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
for k1,v1 in d.iteritems(): # the basic way
temp = ""
temp+=k1
for k2,v2 in v1.iteritems():
temp = temp+" "+str(k2)+" "+str(v2)
print temp
In place of iteritems() you can use items() as well, but iteritems() is much more efficient and returns an iterator.
Hope this helps :)
To get keys and values you need dict.items():
for key, value in d.items():
print(key)
If you want just the keys:
for key in d:
print(key)
you can iterate all keys and values of nested dictionary as following:
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
for i in d:
for j, k in d[i].items():
print(j,"->", k)
Your output looks like this -
foo -> 1
bar -> 2
baz -> 3
quux -> 4
Iterating through a dictionary only gives you the keys.
You told python to expect a bunch of tuples, and it tried to unpack something that wasn't a tuple (your code is set up to expect each iterated item to be of the form (key,value), which was not the case (you were simply getting key on each iteration).
You also tried to print Key, which is not the same as key, which would have led to a NameError.
for key in d:
print(key)
should work.
if given dictionary pattern has monotone format and keys are known
dict_ = {'0': {'foo': 1, 'bar': 2}, '1': {'foo': 3, 'bar': 4}}
for key, val in dict_.items():
if isinstance(val, dict):
print(val.get('foo'))
print(val.get('bar'))
in this case we can skip nested loop
You could use benedict (a dict subclass) and the traverse utility method:
Installation: pip install python-benedict
from benedict import benedict
d = benedict({'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}})
def traverse_item(dct, key, value):
print('key: {} - value: {}'.format(key, value))
d.traverse(traverse_item)
Documentation: https://github.com/fabiocaccamo/python-benedict
Note: I am the author of this project.

How to iterate through a nested dict?

I have a nested python dictionary data structure. I want to read its keys and values without using collection module. The data structure is like bellow.
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
I was trying to read the keys in the dictionary using the bellow way but getting error.
Code
for key, value in d:
print(Key)
Error
ValueError: too many values to unpack (expected 2)
So can anyone please explain the reason behind the error and how to iterate through the dictionary.
keys() method returns a view object that displays a list of all the keys in the dictionary
Iterate nested dictionary:
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
for i in d.keys():
print i
for j in d[i].keys():
print j
OR
for i in d:
print i
for j in d[i]:
print j
output:
dict1
foo
bar
dict2
baz
quux
where i iterate main dictionary key and j iterate the nested dictionary key.
The following will work with multiple levels of nested-dictionary:
def get_all_keys(d):
for key, value in d.items():
yield key
if isinstance(value, dict):
yield from get_all_keys(value)
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'dict3': {'baz': 3, 'quux': 4}}}
for x in get_all_keys(d):
print(x)
This will give you:
dict1
foo
bar
dict2
dict3
baz
quux
As the requested output, the code goes like this
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
for k1,v1 in d.iteritems(): # the basic way
temp = ""
temp+=k1
for k2,v2 in v1.iteritems():
temp = temp+" "+str(k2)+" "+str(v2)
print temp
In place of iteritems() you can use items() as well, but iteritems() is much more efficient and returns an iterator.
Hope this helps :)
To get keys and values you need dict.items():
for key, value in d.items():
print(key)
If you want just the keys:
for key in d:
print(key)
you can iterate all keys and values of nested dictionary as following:
d = {'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}}
for i in d:
for j, k in d[i].items():
print(j,"->", k)
Your output looks like this -
foo -> 1
bar -> 2
baz -> 3
quux -> 4
Iterating through a dictionary only gives you the keys.
You told python to expect a bunch of tuples, and it tried to unpack something that wasn't a tuple (your code is set up to expect each iterated item to be of the form (key,value), which was not the case (you were simply getting key on each iteration).
You also tried to print Key, which is not the same as key, which would have led to a NameError.
for key in d:
print(key)
should work.
if given dictionary pattern has monotone format and keys are known
dict_ = {'0': {'foo': 1, 'bar': 2}, '1': {'foo': 3, 'bar': 4}}
for key, val in dict_.items():
if isinstance(val, dict):
print(val.get('foo'))
print(val.get('bar'))
in this case we can skip nested loop
You could use benedict (a dict subclass) and the traverse utility method:
Installation: pip install python-benedict
from benedict import benedict
d = benedict({'dict1': {'foo': 1, 'bar': 2}, 'dict2': {'baz': 3, 'quux': 4}})
def traverse_item(dct, key, value):
print('key: {} - value: {}'.format(key, value))
d.traverse(traverse_item)
Documentation: https://github.com/fabiocaccamo/python-benedict
Note: I am the author of this project.

python trim down dictionaries in a list of dictionaries

i have the following list which can contain multiple dictionaries of different sizes.
The keys in each dictionary are unique, but one key may exist in different dictionaries. Values are unique across dictionaries.
I want to trim down my dictionaries so that they contain the keys and values for which the value is the highest among all dictionaries.
For example, the key '1258' exists in three of the four dictionaries, and it has the highest value only in the last one, so in the reconstructed list, this key and its value will be in the last dictionary only.
If the key doesn't exist in other dictionaries, then it will remain in the dictionary where it belongs to.
here is sample data:
[{'1258': 1.0167004,
'160': 1.5989301000000002,
'1620': 1.3058813000000002,
'2571': 0.7914598,
'26': 4.554409,
'2943': 0.5072369,
'2951': 0.4955711,
'2952': 1.2380746000000002,
'2953': 1.6159719,
'2958': 0.4340355,
'2959': 0.6026906,
'2978': 0.619001,
'2985': 1.5677016,
'3075': 1.04948,
'3222': 0.9721148000000001,
'3388': 1.680108,
'341': 0.8871856,
'3443': 0.6000103,
'361': 2.6682623000000003,
'4': 5.227341,
'601': 2.2614983999999994,
'605': 0.6303175999999999,
'9': 5.0326675},
{'1457': 5.625237999999999,
'1469': 25.45585200000001,
'1470': 25.45585200000001,
'160': 0.395728,
'1620': 0.420267,
'2571': 0.449151,
'26': 0.278281,
'601': 0.384822,
'605': 5.746278700000001,
'9': 1.487241},
{'1258': 0.27440200000000003,
'1457': 0.8723639999999999,
'1620': 0.182567,
'2571': 0.197134,
'2943': 0.3461654,
'2951': 0.47372800000000004,
'2952': 0.6662919999999999,
'2953': 0.6725458,
'2958': 0.4437159,
'2959': 0.690856,
'2985': 0.8106226999999999,
'3075': 0.352618,
'3222': 0.7866500000000001,
'3388': 0.760664,
'3443': 0.129771,
'601': 0.345448,
'605': 1.909823,
'9': 0.888999},
{'1258': 1.0853083,
'160': 0.622579,
'1620': 0.7419095,
'2571': 0.9828758,
'2943': 2.254124,
'2951': 0.6294688,
'2952': 1.0965362,
'2953': 1.8409954000000002,
'2958': 0.7394122999999999,
'2959': 0.9398920000000001,
'2978': 0.672122,
'2985': 1.2385512999999997,
'3075': 0.912366,
'3222': 0.8364904,
'3388': 0.37316499999999997,
'341': 1.0399186,
'3443': 0.547093,
'361': 0.3313275,
'601': 0.5318834,
'605': 0.2909876}]
Here's one approach. I shortened your example to one that's easier to reason about.
>>> dcts = [
... {1:2, 3:4, 5:6},
... {1:3, 6:7, 8:9},
... {6:10, 8:11, 9:12}]
>>>
>>> [{k:v for k,v in d.items() if v == max(d.get(k) for d in dcts)} for d in dcts]
[{3: 4, 5: 6}, {1: 3}, {8: 11, 9: 12, 6: 10}]
edit:
more efficient because the max is only computed once for each key:
>>> from operator import or_
>>> from functools import reduce
>>> allkeys = reduce(or_, (d.viewkeys() for d in dcts))
>>> max_vals = {k:max(d.get(k) for d in dcts) for k in allkeys}
>>> result = [{k:v for k,v in d.items() if v == max_vals[k]} for d in dcts]
>>> result
[{3: 4, 5: 6}, {1: 3}, {8: 11, 9: 12, 6: 10}]

insert or update keys in a python dictionary

I have a python dictionary dict1 with more than 20,000 keys and I want to update it with another dictionary dict2. The dictionaries look like this:
dict1
key11=>[value11]
key12=>[value12]
...
...
keyxyz=>[value1x] //common key
...... so on
dict2
key21=>[value21]
key22=>[value22]
...
...
keyxyz=>[value2x] // common key
........ so on
If I use
dict1.update(dict2)
then the keys of dict1 which are similar to keys of dict2 will have their values overwritten by values of dict2. What I want is if a key is already present in dict1 then the value of that key in dict2 should be appended to value of dict1. So
dict1.conditionalUpdate(dict2)
should result in
dict1
key11=>[value11]
key12=>[value12]
key21=>[value21]
key22=>[value22]
...
...
keyxyz=>[value1x,value2x]
A naive method would be iterating over keys of dict2 for each key of dict1 and insert or update keys. Is there a better method? Does python support a built in data structure that supports this kind of functionality?
Use defaultdict from the collections module.
>>> from collections import defaultdict
>>> dict1 = {1:'a',2:'b',3:'c'}
>>> dict2 = {1:'hello', 4:'four', 5:'five'}
>>> my_dict = defaultdict(list)
>>> for k in dict1:
... my_dict[k].append(dict1[k])
...
>>> for k in dict2:
... my_dict[k].append(dict2[k])
...
>>> my_dict[1]
['a', 'hello']
This is actually pretty simple to do using a dict comprehension and itertools.groupby():
dict1 = {1: 1, 2: 2, 3: 3, 4: 4}
dict2 = {5: 6, 7: 8, 1: 1, 2: 2}
from itertools import groupby, chain
from operator import itemgetter
sorted_items = sorted(chain(dict1.items(), dict2.items()))
print({key: [value[1] for value in values] for key, values in groupby(sorted_items, itemgetter(0))})
Gives us:
{1: [1, 1], 2: [2, 2], 3: [3], 4: [4], 5: [6], 7: [8]}
Naturally, this creates a new dict, but if you need to update the first dict, you can do that trivially by updating with the new one. If your values are already lists, this may need some minor modification (but I presume you were doing that for the sake of the operation, in which case, there is no need).
Naturally, if you are using Python 2.x, then you will want to use dict.viewitems() or dict.iteritems() over dict.items(). If you are using a version of Python prior to dict comprehensions, then you could use dict((key , value) for ...) instead.
Another method without importing anything, just with the regular Python dictionary:
>>> dict1 = {1:'a',2:'b',3:'c'}
>>> dict2 = {1:'hello', 4:'four', 5:'five'}
>>> for k in dict2:
... dict1[k] = dict1.get(k,"") + dict2.get(k)
...
>>> dict1
{1: 'ahello', 2: 'b', 3: 'c', 4: 'four', 5: 'five'}
>>>
dict1.get(k,"") returns the value associated to k if it exists or an empty string otherwise, and then append the content of dict2.

How to swap keys for values in a dictionary [duplicate]

This question already has answers here:
Reverse / invert a dictionary mapping
(32 answers)
Closed 10 months ago.
I receive a dictionary as input, and would like to to return a dictionary whose keys will be the input's values and whose value will be the corresponding input keys. Values are unique.
For example, say my input is:
a = dict()
a['one']=1
a['two']=2
I would like my output to be:
{1: 'one', 2: 'two'}
To clarify I would like my result to be the equivalent of the following:
res = dict()
res[1] = 'one'
res[2] = 'two'
Any neat Pythonic way to achieve this?
Python 2:
res = dict((v,k) for k,v in a.iteritems())
Python 3 (thanks to #erik):
res = dict((v,k) for k,v in a.items())
new_dict = dict(zip(my_dict.values(), my_dict.keys()))
From Python 2.7 on, including 3.0+, there's an arguably shorter, more readable version:
>>> my_dict = {'x':1, 'y':2, 'z':3}
>>> {v: k for k, v in my_dict.items()}
{1: 'x', 2: 'y', 3: 'z'}
You can make use of dict comprehensions:
Python 3
res = {v: k for k, v in a.items()}
Python 2
res = {v: k for k, v in a.iteritems()}
Edited: For Python 3, use a.items() instead of a.iteritems(). Discussions about the differences between them can be found in iteritems in Python on SO.
In [1]: my_dict = {'x':1, 'y':2, 'z':3}
Python 3
In [2]: dict((value, key) for key, value in my_dict.items())
Out[2]: {1: 'x', 2: 'y', 3: 'z'}
Python 2
In [2]: dict((value, key) for key, value in my_dict.iteritems())
Out[2]: {1: 'x', 2: 'y', 3: 'z'}
The current leading answer assumes values are unique which is not always the case. What if values are not unique? You will loose information!
For example:
d = {'a':3, 'b': 2, 'c': 2}
{v:k for k,v in d.iteritems()}
returns {2: 'b', 3: 'a'}.
The information about 'c' was completely ignored.
Ideally it should had be something like {2: ['b','c'], 3: ['a']}. This is what the bottom implementation does.
Python 2.x
def reverse_non_unique_mapping(d):
dinv = {}
for k, v in d.iteritems():
if v in dinv:
dinv[v].append(k)
else:
dinv[v] = [k]
return dinv
Python 3.x
def reverse_non_unique_mapping(d):
dinv = {}
for k, v in d.items():
if v in dinv:
dinv[v].append(k)
else:
dinv[v] = [k]
return dinv
You could try:
Python 3
d={'one':1,'two':2}
d2=dict((value,key) for key,value in d.items())
d2
{'two': 2, 'one': 1}
Python 2
d={'one':1,'two':2}
d2=dict((value,key) for key,value in d.iteritems())
d2
{'two': 2, 'one': 1}
Beware that you cannot 'reverse' a dictionary if
More than one key shares the same value. For example {'one':1,'two':1}. The new dictionary can only have one item with key 1.
One or more of the values is unhashable. For example {'one':[1]}. [1] is a valid value but not a valid key.
See this thread on the python mailing list for a discussion on the subject.
res = dict(zip(a.values(), a.keys()))
new_dict = dict( (my_dict[k], k) for k in my_dict)
or even better, but only works in Python 3:
new_dict = { my_dict[k]: k for k in my_dict}
Another way to expand on Ilya Prokin's response is to actually use the reversed function.
dict(map(reversed, my_dict.items()))
In essence, your dictionary is iterated through (using .items()) where each item is a key/value pair, and those items are swapped with the reversed function. When this is passed to the dict constructor, it turns them into value/key pairs which is what you want.
Suggestion for an improvement for Javier answer :
dict(zip(d.values(),d))
Instead of d.keys() you can write just d, because if you go through dictionary with an iterator, it will return the keys of the relevant dictionary.
Ex. for this behavior :
d = {'a':1,'b':2}
for k in d:
k
'a'
'b'
Can be done easily with dictionary comprehension:
{d[i]:i for i in d}
dict(map(lambda x: x[::-1], YourDict.items()))
.items() returns a list of tuples of (key, value). map() goes through elements of the list and applies lambda x:[::-1] to each its element (tuple) to reverse it, so each tuple becomes (value, key) in the new list spitted out of map. Finally, dict() makes a dict from the new list.
Hanan's answer is the correct one as it covers more general case (the other answers are kind of misleading for someone unaware of the duplicate situation). An improvement to Hanan's answer is using setdefault:
mydict = {1:a, 2:a, 3:b}
result = {}
for i in mydict:
result.setdefault(mydict[i],[]).append(i)
print(result)
>>> result = {a:[1,2], b:[3]}
Using loop:-
newdict = {} #Will contain reversed key:value pairs.
for key, value in zip(my_dict.keys(), my_dict.values()):
# Operations on key/value can also be performed.
newdict[value] = key
If you're using Python3, it's slightly different:
res = dict((v,k) for k,v in a.items())
Adding an in-place solution:
>>> d = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> for k in list(d.keys()):
... d[d.pop(k)] = k
...
>>> d
{'two': 2, 'one': 1, 'four': 4, 'three': 3}
In Python3, it is critical that you use list(d.keys()) because dict.keys returns a view of the keys. If you are using Python2, d.keys() is enough.
I find this version the most comprehensive one:
a = {1: 'one', 2: 'two'}
swapped_a = {value : key for key, value in a.items()}
print(swapped_a)
output :
{'one': 1, 'two': 2}
An alternative that is not quite as readable (in my opinion) as some of the other answers:
new_dict = dict(zip(*list(zip(*old_dict.items()))[::-1]))
where list(zip(*old_dict.items()))[::-1] gives a list of 2 tuples, old_dict's values and keys, respectively.

Categories

Resources