Reversing a Dict - python

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

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

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.

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.

Related

Find non-Empty value in dict

I have a dict like this:
d = {'first':'', 'second':'', 'third':'value', 'fourth':''}
and I want to find first non-empty value (and it's name, in this example 'third'). There may be more than one non-empty value, but I only want the first one I find.
How can I do this?
Use an OrderedDict which preserves the order of elements. Then loop over them and find the first that isn't empty:
from collections import OrderedDict
d = OrderedDict()
# fill d
for key, value in d.items():
if value:
print(key, " is not empty!")
You could use next (dictionaries are unordered - this somewhat changed in Python 3.6 but that's only an implementation detail currently) to get one "not-empty" key-value pair:
>>> next((k, v) for k, v in d.items() if v)
('third', 'value')
Like this?
def none_empty_finder(dict):
for e in dict:
if dict[e] != '':
return [e,dict[e]]
d = {'first':'', 'second':'', 'third':'value', 'fourth':''}
for k, v in d.items():
if v!='':
return k, v
Edit 1
from the comment if the value is None or '' we better use if v: instead of if v!=''. if v!='' only check the '' and skip others
You can find empty elements and make a list of them:
non_empty_list = [(k,v) for k,v in a.items() if v]
By using list comprehension, you can list all the non-empty values and then fetch the 0th value:
[val for key, val in d.items() if val][0]

How do I loop over a map object's 2ND value in reverse?

I have a map and I am using a for loop to loop through it, but it only gives me the first value,.in ascending order. Any help appreciated!
What do you mean by ascending order? You could sort them:
Python 2.7
for v in sorted(map.itervalues()):
print v
Python 3
for v in sorted(map.values()):
print v
If instead you wanted keys to be sorted, try:
for _, v in sorted(map.items()):
print v
I'm assuming that by map you mean a dict, by "first value" you mean key, and by "second value" you mean value?
You can use .iteritems() to iterate over key/value pairs instead of just keys
d = {'a': 1, 'b': 2}
for k, v in d.iteritems():
print "key:", k
print "value:", v
Or .itervalues() to iterate over just the values:
for v in d.valueitems():
print "value:", v
There's no way to apply ordering to a dict's items directly -- iteration over a dict can occur in any order. You can however iterate over a sorted iteritems():
for k, v in sorted(d.iteritems(), key=lambda k, v: v):
print "key:", k
print "value:", v
Or just the values:
for v in sorted(d.valueitems()):
print "value:", v
It's not very clear what your asking, but I took my best guess. Next time try to post some of your already done code!
>>> mydict = {'a': 1, 'b': 89, 'c': 56, 'd': 9123, 'e':-23}
>>> mylist = []
>>> for k in mydict:
... mylist.append(mydict[k])
...
>>> mylist.sort()
>>> mylist.reverse()
>>> mylist
[9123, 89, 56, 1, -23]
>>>
Explanation:
Lines
Set mydict to some value of numbers (because you want it in reverse)
Set mylist to a blank list
Loop over the first value of the dict
Use the first value to get the second value with mydict[k].
Append that to mylist
Use mylist.sort() to sort in ascending order
Use mylist.reverse() to reverse it.

Sum up values from a dictionary (the Python way)

Given the following dictionary, let's call it mydict
{'Plekhg2': {'Bcells': '233.55', 'DendriticCells': '190.12'},
'Barxxxx': {'Bcells': '132.11', 'DendriticCells': '92.01'}, }
I want to sum up values for each key from inner dictionary, resulting in:
{'Plekhg2': 423.67, # 233.55 + 190.12
'Barxxxx': 224.12} # 132.11 + 92.01
How can I achieve that with Python idiom?
With a dict comprehension, using sum() to sum the nested dictionary values; Python 2.6 or before would use dict() and a generator expression:
# Python 2.7
{k: sum(float(f) for f in v.itervalues()) for k, v in mydict.iteritems()}
# Python 3.x
{k: sum(map(float, v.values())) for k, v in mydict.items()}
# Python 2.6 and before
dict((k, sum(float(f) for f in v.values())) for k, v in mydict.iteritems())
You may want to store float values to begin with though.
Demo:
>>> mydict ={'Plekhg2': {'Bcells': '233.55', 'DendriticCells': '190.12'},
... 'Barxxxx': {'Bcells': '132.11', 'DendriticCells': '92.01'}, }
>>> {k: sum(float(f) for f in v.itervalues()) for k, v in mydict.iteritems()}
{'Plekhg2': 423.67, 'Barxxxx': 224.12}
Use a dict comprehension and sum, since the values are strings you'll have to convert them to floats first using float.
>>> {k:sum(float(x) for x in v.itervalues()) for k, v in d.iteritems()}
{'Plekhg2': 423.67, 'Barxxxx': 224.12}
For Python 3 use .items() and .values() instead of the .iter(values|items).
Just for completion in Python 3:
In [134]:
{k:sum(float(x) for x in v.values()) for k, v in my_dict.items()}
Out[134]:
{'Barxxxx': 224.12, 'Plekhg2': 423.67}

Selecting elements of a Python dictionary greater than a certain value

I need to select elements of a dictionary of a certain value or greater. I am aware of how to do this with lists, Return list of items in list greater than some value.
But I am not sure how to translate that into something functional for a dictionary. I managed to get the tags that correspond (I think) to values greater than or equal to a number, but using the following gives only the tags:
[i for i in dict if dict.values() >= x]
.items() will return (key, value) pairs that you can use to reconstruct a filtered dict using a list comprehension that is feed into the dict() constructor, that will accept an iterable of (key, value) tuples aka. our list comprehension:
>>> d = dict(a=1, b=10, c=30, d=2)
>>> d
{'a': 1, 'c': 30, 'b': 10, 'd': 2}
>>> d = dict((k, v) for k, v in d.items() if v >= 10)
>>> d
{'c': 30, 'b': 10}
If you don't care about running your code on python older than version 2.7, see #opatut answer using "dict comprehensions":
{k:v for (k,v) in dict.items() if v > something}
While nmaier's solution would have been my way to go, notice that since python 2.7+ there has been a "dict comprehension" syntax:
{k:v for (k,v) in dict.items() if v > something}
Found here: Create a dictionary with list comprehension in Python. I found this by googling "python dictionary list comprehension", top post.
Explanation
{ .... } includes the dict comprehension
k:v what elements to add to the dict
for (k,v) in dict.items() this iterates over all tuples (key-value-pairs) of the dict
if v > something a condition that has to apply on every value that is to be included
You want dict[i] not dict.values(). dict.values() will return the whole list of values that are in the dictionary.
dict = {2:5, 6:2}
x = 4
print [dict[i] for i in dict if dict[i] >= x] # prints [5]

The best way to filter a dictionary in Python [duplicate]

This question already has answers here:
How to filter a dictionary according to an arbitrary condition function?
(7 answers)
Closed 7 years ago.
I have a dictionary of string keys and float values.
mydict = {}
mydict["joe"] = 20
mydict["bill"] = 20.232
mydict["tom"] = 0.0
I want to filter the dictionary to only include pairs that have a value greater than zero.
In C#, I would do something like this:
dict = dict.Where(r=>r.Value > 0);
What is the equivalent code in Python?
d = dict((k, v) for k, v in d.iteritems() if v > 0)
In Python 2.7 and up, there's nicer syntax for this:
d = {k: v for k, v in d.items() if v > 0}
Note that this is not strictly a filter because it does create a new dictionary.
Assuming your original dictionary is d1 you could use something like:
d2 = dict((k, v) for k, v in d1.items() if v > 0)
By the way, note that dict is already reserved in python.
The dict constructor can take a sequence of (key,value) pairs, and the iteritems method of a dict produces a sequence of (key,value) pairs. It's two great tastes that taste great together.
newDict = dict([item for item in oldDict.iteritems() if item[1] > 0])
foo = {}
foo["joe"] = 20
foo["bill"] = 20.232
foo["tom"] = 0.0
bar = dict((k,v) for k,v in foo.items() if v>0)
dict is a keyword in Python so I replaced it with foo.
first of all you should not use the keyword dict as a variable name as it pollutes the namespace, and prevents you from referencing the dict class in the current or embedded scope.
d = {}
d["joe"] = 20
d["bill"] = 20.232
d["tom"] = 0.0
# create an intermediate generator that is fed into dict constructor
# via a list comprehension
# this is more efficient that the pure "[...]" variant
d2 = dict(((k, v) for (k, v) in d.iteritems() if v > 0))
print d2
# {'bill': 20.232, 'joe': 20}
Alternatively, you could just create the generator and iterator over it directly. This more like a "filter", because the generator only references the values in the original dict instead of making a subset copy; and hence is more efficient than creating a new dictionary :
filtered = ((k, v) for (k, v) in d.iteritems() if v > 0)
print filtered
# <generator object <genexpr> at 0x034A18F0>
for k, v in filtered:
print k, v
# bill 20.232
# joe 20
try
y = filter(lambda x:dict[x] > 0.0,dict.keys())
the lambda is feed the keys from the dict, and compares the values in the dict for each key, against the criteria, returning back the acceptable keys.

Categories

Resources