Sum up values from a dictionary (the Python way) - python

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}

Related

How to reverse dictionary items and list keys grouped by common values [duplicate]

This question already has answers here:
Dictionary comprehension for swapping keys/values in a dict with multiple equal values
(3 answers)
Closed 2 years ago.
I have a dictionary that I want to group by the common values:
init_dict = {'00001': 'string1', '00002': 'string2', '00003': 'string1', '00004': 'string3', '00005': 'string2'}
I want to create a new dictionary that groups the values and lists the keys like this:
new_dict = {'string1': ['00001', '00003'], 'string2':['00002', '00004'], 'string3': ['00004']}
I tried many things and this is the closest I can get.
lookup = 'string1'
all_keys = []
for k, v in init_dict.items():
if v == lookup:
all_keys.append(k)
print(all_keys)
This produces the first list: ['00001', '00003'] so I thought I could somehow loop through a list of lookup values but can't since I'm working with strings. Is there a way to do this and is there a way that is relatively efficient because my initial dictionary has 53,000 items in it. Any help would be much appreciated as I've been trying different things for hours.
Use a defaultdict, specifying a list as default argument, and append the corresponding values from the dictionary:
from collections import defaultdict
d = defaultdict(list)
for k,v in init_dict.items():
d[v].append(k)
print(d)
defaultdict(list,
{'string1': ['00001', '00003'],
'string2': ['00002', '00005'],
'string3': ['00004']})
You can use defaultdict
result = defaultdict(list)
for k, v in init_dict.items():
result[v].append(k)
or itertools.groupby
result = {k: [x[0] for x in v] for k, v in
groupby(sorted(init_dict.items(), key=lambda kv: kv[1]), key=lambda kv: kv[1])}
You can also use a normal dict (instead of defaultdict):
new_dict = {}
for key, val in init_dict.items():
if val in new_dict:
new_dict[val].append(key)
else:
new_dict[val] = []
new_dict[val].append(key)
Output:
new_dict = {'string1': ['00001', '00003'],
'string2': ['00002', '00005'],
'string3': ['00004']}

Reversing a Dict

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.

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]

Matching lists when elements are not ordered

let's say I have a list b=['m','NN'] and a dictionary dict={'b':['NN','m','big']} and I want to use the function to retrieve the key 'b' if the elements of the list b are in dict[b]
(so let's say using [k for k,v in dict.items()].
Now how do I do that if the elements in b are not ordered as the elements in dict[b] and supposing I cannot change the order in the b list?
Thank you!
Not certain I understand what you're asking, but if what you're after is the list of keys in dictionary d with values which are super-sets of the list b, you could use something like:
b=['m','NN']
d={'b':['NN','m','big'], 'a':['jj','r']}
[k for k,v in d.items() if set(b) <= set(v)]
(I changed the name of your example dictionary as dict is a built-in class.)
You can do:
[k for k, v in dict.items() if all((x in v) for x in b)]
For example:
>>> b=['m','NN']
>>> dict={'b':['NN','m','big'], 'a':['NN', 'q']}
>>> [k for k, v in dict.items() if all((x in v) for x in b)]
['b']
(Note that it is a bad idea to name your dictionary dict, since dict is the name of the data type).

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