Reputation: 215
I am currently trying to make a function which reverses a dict's keys and values. I was looking online and came across this:
def reverse(d):
return dict([(v, k) for k, v in d.iteritems()])
My problem is that I'm not sure what this means. I understand the idea of a for loop on the single line but I'm not sure how the (v, k) for k, v leads to the keys and values being reversed. Could someone please offer me a hand. (I did search for this, both online and on Stack Overflow but couldn't find anything.)
Upvotes: 1
Views: 200
Reputation: 180471
for k, v in d.iteritems()
is each key k
and value v
so reversing v and k with (v, k)
makes the old value the key and the old key the new value
In [7]: d = {1:10,2:20}
In [8]: d.items()
Out[8]: dict_items([(1, 10), (2, 20)]) # tuples of key and value
In [1]: d = {1:10,2:20}
In [2]: for k,v in d.iteritems():
print k,v
...:
1 10 # 1 is the key 10 is the value
2 20
In [3]: new_d = {v:k for k,v in d.iteritems()} # swap key for value and value for key
In [4]: new_d
Out[4]: {10: 1, 20: 2}
Two problems you may encounter are duplicate values or values that are not hashable so they cannot be used as keys like lists, sets etc...
In [5]: d = {1:2,2:2}
In [6]: new_d = {v:k for k,v in d.iteritems()}
In [7]: new_d
Out[7]: {2: 2} # now only one key and value in the dict
In [8]: d = {1:2,2:[2]}
In [9]: new_d = {v:k for k,v in d.iteritems()}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-46a3901ce850> in <module>()
----> 1 new_d = {v:k for k,v in d.iteritems()}
<ipython-input-9-46a3901ce850> in <dictcomp>((k, v))
----> 1 new_d = {v:k for k,v in d.iteritems()}
TypeError: unhashable type: 'list'
dict([(v, k) for k, v in d.iteritems()])
will have the same output as {v:k for k,v in d.iteritems()}
, the main difference is the former is also compatible with python < 2.7.
If you were using python < 2.7 there is no need to use a list you can just use a generator expression:
dict((v, k) for k, v in d.iteritems())
Upvotes: 4
Reputation: 60150
OK, so when you call iteritems()
on a dict, it gives you a (key, value)
tuple for each item in your dictionary:
for item in d.iteritems():
print(item)
Then you can assign each item in the tuple to a separate variable using Python's tuple unpacking syntax:
a, b = (1, 2)
print(a) # 1
print(b) # 2
And if you pass a list of tuples to dict()
, it treats them as a list
of (key, value)
items:
eg_dict = dict([(a, 4), (b, 6)])
print(eg_dict)
Finally, the example you posted makes use of Python's list comprehension syntax:
item_list = ['item' + str(n) for n in range(1, 6)]
print(item_list)
To understand the code snippet you've posted, you just need to be familiar with these Python idioms. If you haven't seen any of these techniques before then it's a fairly dense burst of new information to get your head around.
Upvotes: 1
Reputation: 606
the dict constructor can receive an iterable of key/value pairs to create a dictionary, so this code is saying "grab the key/value pairs from this dictionary d and create a new dictionary where the values of d are now the keys and the keys of d become the values"
That is why that the (v,k) are reversed, if you did NOT reverse them, like this
def reverse(d):
return dict([(k, v) for k, v in d.iteritems()])
you would get an identical dictionary back.
also note that in python 2.7 and later you can actually use the even more compact:
{v:k for k,v in d.items()}
Which reads more intuitively (at least to me) because it looks more like a list comprehension, only it creates a dict.
Upvotes: 1