For each value in dict? - python

I've got a dict with integer values, and I'd like to perform an operation on every value in the dict. I'd like to use a for loop for this, but I can't get it right. Something like:
>>>print(myDict)
{'ten': 10, 'fourteen': 14, 'six': 6}
>>>for value in myDict:
... value = value / 2
>>>print(myDict)
{'ten': 5, 'fourteen': 7, 'six': 3}

To iterate over keys and values:
for key, value in myDict.items():
myDict[key] = value / 2
The default loop over a dictionary iterates over its keys, like
for key in myDict:
myDict[key] /= 2
or you could use a map or a comprehension.
map:
myDict = map(lambda item: (item[0], item[1] / 2), myDict)
comprehension:
myDict = { k: v / 2 for k, v in myDict.items() }

for k in myDict:
myDict[k] /= 2

Using the dict.items() method and a dict comprehension:
dic = {'ten': 10, 'fourteen': 14, 'six': 6}
print({k: v/2 for k, v in dic.items()})
Output:
{'ten': 5.0, 'six': 3.0, 'fourteen': 7.0}

Python 3:
>>> my_dict = {'ten': 10, 'fourteen': 14, 'six': 6}
>>> for key, value in my_dict.items():
my_dict[key] = value / 2
>>> my_dict
{'fourteen': 7.0, 'six': 3.0, 'ten': 5.0}
This changes the original dictionary. Use // instead of / to get floor division.

Related

How to returns a list of all values corresponding to keys greater than x in the dictionary [duplicate]

This question already has answers here:
Iterating over dictionaries using 'for' loops
(15 answers)
How to filter a dictionary according to an arbitrary condition function?
(7 answers)
Closed 12 months ago.
I need to use for For loop to find the return the list of values in a dictionary greater than x.
d= {}
for key in d():
if key > x:
return(d(key))
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}
values_list = list(d.values())
>>> values_list
[30, 10]
We hold greater_than_x list, and append the values in d dictionary if it's bigger than the given x.
x = 20
greater_than_x = []
d = {"a": 10, "b": 20, "c": 30}
for value in d.values():
if value > x:
greater_than_x.append(value)
print(greater_than_x)
>[30]
One-liner applying the same logic:
x = 20
d = {"a": 10, "b": 20, "c": 30}
greater_than_x = [value for value in d.values() if value > x]
print(greater_than_x)
>[30]

Choose dictionary keys only if their values don't have a certain number of duplicates

Given a dictionary and a limit for the number of keys in a new dictionary, I would like the new dictionary to contain the keys with the highest values.
The given dict is:
dict = {'apple':5, 'pears':4, 'orange':3, 'kiwi':3, 'banana':1 }
I want to get a new dictionary that has the keys with the highest values of length limit.
For instance for limit=1 the new dict is
{'apple':5}
if the limit=2
{'apple':5, 'pears':4}
I tried this:
return dict(sorted(dictation.items(),key=lambda x: -x[1])[:limit])
but when I try limit=3, I get
{'apple':5, 'pears':4, 'orange':3}
But it shouldn't include orange:3 because orange and kiwi have same priority if we include kiwi and orange it will exceed the limit so it shouldn't include both. I should return
{'apple':5, 'pears':4}
The way to go would be to use a collections.Counter and most_common(n). Then you can take one more as needed and keep popping until the last value changes:
from collections import Counter
dct = {'apple':5, 'pears':4, 'orange':3, 'kiwi':3, 'banana':1}
n = 3
items = Counter(dictation).most_common(n+1)
last_val = items[-1][1]
if len(items) > n:
while items[-1][1] == last_val:
items.pop()
new = dict(items)
# {'apple': 5, 'pears': 4}
This is computationally not very good, but it works. It creates a Counter object to get the sorted output for your data and a inverted defaultdict that holds list that match to a score - it creates the result using both and some math:
from collections import defaultdict, Counter
def gimme(d,n):
c = Counter(d)
grpd = defaultdict(list)
for key,value in c.items():
grpd[value].append(key)
result = {}
for key,value in c.most_common():
if len(grpd[value])+len(result) <= n:
result.update( {k:value for k in grpd[value] } )
else:
break
return result
Test:
data = {'apple':5, 'pears':4, 'orange':3, 'kiwi':3, 'banana':1 }
for k in range(10):
print(k, gimme(data,k))
Output:
0 {}
1 {'apple': 5}
2 {'apple': 5, 'pears': 4}
3 {'apple': 5, 'pears': 4}
4 {'apple': 5, 'pears': 4, 'orange': 3, 'kiwi': 3}
5 {'apple': 5, 'pears': 4, 'orange': 3, 'kiwi': 3}
6 {'apple': 5, 'pears': 4, 'orange': 3, 'kiwi': 3, 'banana': 1}
7 {'apple': 5, 'pears': 4, 'orange': 3, 'kiwi': 3, 'banana': 1}
8 {'apple': 5, 'pears': 4, 'orange': 3, 'kiwi': 3, 'banana': 1}
9 {'apple': 5, 'pears': 4, 'orange': 3, 'kiwi': 3, 'banana': 1}
As you note, filtering by the top n doesn't exclude by default all equal values which exceed the stated cap. This is by design.
The trick is to consider the (n+1) th highest value and ensure the values in your dictionary are all higher than this number:
from heapq import nlargest
dictation = {'apple':5, 'pears':4, 'orange':3, 'kiwi':3, 'banana':1}
n = 3
largest_items = nlargest(n+1, dictation.items(), key=lambda x: x[1])
n_plus_one_value = largest_items[-1][1]
res = {k: v for k, v in largest_items if v > n_plus_one_value}
print(res)
{'apple': 5, 'pears': 4}
We assume here len(largest_items) < n, otherwise you can just take the input dictionary as the result.
The dictionary comprehension seems expensive. For larger inputs, you can use bisect, something like:
from heapq import nlargest
from operator import itemgetter
from bisect import bisect
dictation = {'apple':5, 'pears':4, 'orange':3, 'kiwi':3, 'banana':1}
n = 3
largest_items = nlargest(n+1, dictation.items(), key=lambda x: x[1])
n_plus_one_value = largest_items[-1][1]
index = bisect(list(map(itemgetter(1), largest_items))[::-1], n_plus_one_value)
res = dict(largest_items[:len(largest_items) - index])
print(res)
{'apple': 5, 'pears': 4}

Python 3.6: create new dict using values from another as indices

In Python 3.6.3, I have the following dict D1:
D1 = {0: array([1, 2, 3], dtype=int64), 1: array([0,4], dtype=int64)}
Each value inside the array is the index of the key of another dict D2:
D2 = {'Jack': 1, 'Mike': 2, 'Tim': 3, 'Paul': 4, 'Tommy': 5}
I am trying to create a third dict, D3, with the same keys as D1, and as values the keys of D2 corresponding to the indices of D1.values().
The result I am aiming for is:
D3 = {0: ['Mike','Tim','Paul'], 1: ['Jack','Tommy']}
My approach is partial in that I struggle to figure out how to tell D3 to get the keys from D1 and the values from D2. I am not too sure about that and. Any ideas?
D3 = {key:list(D1.values())[v] for key in D1.keys() and v in D2[v]}
You could use a dict-comprehension like so:
from numpy import array
D1 = {0: array([1, 2, 3]), 1: array([0,4])}
D2 = {'Jack': 1, 'Mike': 2, 'Tim': 3, 'Paul': 4, 'Tommy': 5}
temp = dict(zip(D2.values(), D2.keys())) # inverting key-value pairs
D3 = {k: [temp.get(i+1, 'N\A') for i in v] for k, v in D1.items()}
which results in:
{0: ['Mike', 'Tim', 'Paul'], 1: ['Jack', 'Tommy']}
If you're using Python 3.6+ you can use enumerate to create a dict to look up the names in D2 by index, and then map the indices in D1 to it:
r = dict(enumerate(D2))
D3 = {k: list(map(r.get, v)) for k, v in D1.items()}
D3 would become:
{0: ['Mike', 'Tim', 'Paul'], 1: ['Jack', 'Tommy']}
This is untested, but I believe this should get you headed in the right direction. I find it helpful sometimes to break out a complicated one-liner into multiple lines
D3={}
for d1k,d1v in D1.items():
D3[d1k] = []
for idx in d1v:
D3[d1k].append(D2[idx])
Might not be the best solution but works
D3={}
for key in D1.keys():
value_list=D1.get(key)
value_list= [(lambda x: x+1)(x) for x in value_list]
temp=[]
for d2_key,value in D2.items():
if value in value_list:
temp.append(d2_key)
D3[key]=temp
Output:
{0: ['Tim', 'Mike', 'Paul'], 1: ['Jack', 'Tommy']}
Here you go!
D1 = {0:[1, 2, 3], 1: [0,4]}
D2 = {'Jack': 1, 'Mike': 2, 'Tim': 3, 'Paul': 4, 'Tommy': 5}
D2_inverted = {v: k for k, v in D2.iteritems()}
D3={}
for key in D1:
temp = []
for value in D1[key]:
temp.append(D2_inv[value+1])
D3[key] = temp
print D3
Iterate the keys from D1;
Create a temporary list to store the values you wish to assign to the new dict, and fill it with the desired values from D2. (inverted its keys and values for simplicity);
Assign to D3.

Filter dictionary and remove lowest values

I have dictionary as below. Is there a way to output a dictionary with the 5 highest values?
If there are ties for the 5th highest value, I need to include those keys.
Input dictionary:
{
"1": 1,
"12": 1,
"13":2,
"3": 5,
"5":8,
"7":3,
"4":8,
"10":7
}
Desired result:
{
"3": 5,
"5":8,
"7":3,
"4":8,
"10":7
}
Accounting for ties:
val = sorted(d.values(), reverse=True)[4]
res = {k: v for k, v in d.items() if v >= val}
print(res)
{'3': 5, '5': 8, '7': 3, '4': 8, '10': 7}
Explanation
Calculate the 5th highest value using sorted with reverse=True. Remember indexing begins at 0 so index with [4].
Use a dictionary comprehension to select all items from your dictionary where value is greater than the calculated value.
Optimisation
A more efficient method, as pointed out by #Chris_Rands, is to use heapq to calculate the 5th highest value:
import heapq
val = heapq.nlargest(5, d.values())[-1]
res = {k: v for k, v in d.items() if v >= val}
from collections import Counter
dict(Counter(your_dict).most_common(5))
OUTPUT:
{'10': 7, '3': 5, '4': 8, '5': 8, '7': 3}

Sum values of similar keys inside two nested dictionary in python

I have nested dictionary like this:
data = {
"2010":{
'A':2,
'B':3,
'C':5,
'D':-18,
},
"2011":{
'A':1,
'B':2,
'C':3,
'D':1,
},
"2012":{
'A':1,
'B':2,
'C':4,
'D':2
}
}
In my case, i need to sum all values based on its similar keys in every year, from 2010 till 2012..
So the result i expected should be like this:
data = {'A':4,'B':7, 'C':12, 'D':-15}
You can use collections.Counter() (works only for positive values!):
In [17]: from collections import Counter
In [18]: sum((Counter(d) for d in data.values()), Counter())
Out[18]: Counter({'C': 12, 'B': 7, 'A': 4, 'D': 3})
Note that based on python documentation Counter is designed only for use cases with positive values:
The multiset methods are designed only for use cases with positive values. The inputs may be negative or zero, but only outputs with positive values are created. There are no type restrictions, but the value type needs to support addition, subtraction, and comparison.
The elements() method requires integer counts. It ignores zero and negative counts.
So if you want to get a comprehensive result you can do the summation manually. The collections.defaultdict() is a good way for getting around this problem:
In [28]: from collections import defaultdict
In [29]: d = defaultdict(int)
In [30]: for sub in data.values():
....: for i, j in sub.items():
....: d[i] += j
....:
In [31]: d
Out[31]: defaultdict(<class 'int'>, {'D': -15, 'A': 4, 'C': 12, 'B': 7})
Try this,
reduce(lambda x, y: dict((k, v + y[k]) for k, v in x.iteritems()), data.values())
Result
{'A': 4, 'B': 7, 'C': 12, 'D': -15}

Categories

Resources