Related
I have a list of dictionaries and a separate dictionary having the same keys and only the values are different. For example the list of dictionaries look like this:
[{'A': 0.102, 'B': 0.568, 'C': 0.33}, {'A': 0.026, 'B': 0.590, 'C': 0.382}, {'A': 0.005, 'B': 0.857, 'C': 0.137}, {'A': 0.0, 'B': 0.962, 'C': 0.036}, {'A': 0.0, 'B': 0.991, 'C': 0.008}]
and the separate dictionary looks like this:
{'A': 0.005, 'B': 0.956, 'C': 0.038}
I want to compare the separate dictionary with the list of dictionaries and return the index from the list which has higher value than the separate dictionary. In this example, the indices would be 3, 4 as the dictionary in indices 3 and 4 has a higher value for key 'B' since 'B' has the highest value in the separate dictionary.
Any ideas on how I should I proceed the problem?
You can use enumerate for finding index of max value:
org = [
{'A': 0.102, 'B': 0.568, 'C': 0.33},
{'A': 0.026, 'B': 0.590, 'C': 0.382},
{'A': 0.005, 'B': 0.857, 'C': 0.137},
{'A': 0.0, 'B': 0.962, 'C': 0.036},
{'A': 0.0, 'B': 0.991, 'C': 0.008}
]
com = {'A': 0.005, 'B': 0.956, 'C': 0.038}
def fnd_index(org, com):
key_max, val_max = max(com.items(), key=lambda x: x[1])
print('key_max:', key_max)
print('val_max:', val_max)
res = []
for idx, dct in enumerate(org):
if dct[key_max] > val_max:
res.append(idx)
return res
res = fnd_index(org, com)
print('result:', res)
Output:
key_max: B
val_max: 0.956
result: [3, 4]
are you sure that it should be only index 4?
dict_list = [{'A': 0.102, 'B': 0.568, 'C': 0.33},
{'A': 0.026, 'B': 0.590, 'C': 0.382},
{'A': 0.005, 'B': 0.857, 'C': 0.137},
{'A': 0.0, 'B': 0.962, 'C': 0.036},
{'A': 0.0, 'B': 0.991, 'C': 0.008}]
d = {'A': 0.005, 'B': 0.956, 'C': 0.038}
max_val = max(d.values())
idxmax = [i for i,j in enumerate(dict_list) if max(j.values()) > max_val]
print(idxmax) # [3, 4]
This question already has answers here:
How to sum values in multidimensional dictionary?
(6 answers)
Closed 1 year ago.
I have this nested dictionary:
{'rekless': {'C': 2.0, 'H': 4.0, 'J': 0.0}, 'bwipo': {'C': 3.0, 'D': 4.0, 'H': 0.0}, 'wunder': {'D': 10.0, 'G': 20.0, 'H': 0.50}, 'caps': {'D': 3.1, 'I': 2.0, '9J': 1.0, '10K': 2.0}, 'jankos': {'D': 3.2, 'I': 2.0, 'J': 1.0, 'K': 2.0} }
Want i want to do is to loop through it and sum all values of the "C, H, J,", etc...
So like, 'C' is going to be (2.0 + 3.0), 'D' is going to be (4.0 + 10.0 + 3.1 + 3.2).
So i can end up with something similar to this:
{ C: 'sum of values from c', D: 'sum of values from d', etc.. }
It doesnt need to be in a dictionary the final result.
Any ideias on how to start?
You need to loop through both dictionary and subdictionary:
d = {
'rekless': {'C': 2.0, 'H': 4.0, 'J': 0.0},
'bwipo': {'C': 3.0, 'D': 4.0, 'H': 0.0},
'wunder': {'D': 10.0, 'G': 20.0, 'H': 0.50},
'caps': {'D': 3.1, 'I': 2.0, '9J': 1.0, '10K': 2.0},
'jankos': {'D': 3.2, 'I': 2.0, 'J': 1.0, 'K': 2.0}
}
summary = dict()
for key, subdict in d.items():
for k, v in subdict.items():
summary[k] = summary.get(k, 0) + v
print(summary)
Assume d is:
d = {'rekless': {'C': 2.0, 'H': 4.0, 'J': 0.0}, 'bwipo': {'C': 3.0, 'D': 4.0, 'H': 0.0}, 'wunder': {'D': 10.0, 'G': 20.0, 'H': 0.50}, 'caps': {'D': 3.1, 'I': 2.0, '9J': 1.0, '10K': 2.0}, 'jankos': {'D': 3.2, 'I': 2.0, 'J': 1.0, 'K': 2.0} }
Try this:
vals ={}
for k in d:
sum_ = 0
for k_ in d[k]:
if k_ in vals:
vals[k_]+= int(d[k][k_])
else:
vals[k_]= int(d[k][k_])
for k__ in vals:
vals[k__]='sum of values from {} is: {}'.format(k__, vals[k__])
which results in vals to be:
{'C': 'sum of values from C is: 5',
'H': 'sum of values from H is: 4',
'J': 'sum of values from J is: 1',
'D': 'sum of values from D is: 20',
'G': 'sum of values from G is: 20',
'I': 'sum of values from I is: 4',
'9J': 'sum of values from 9J is: 1',
'10K': 'sum of values from 10K is: 2',
'K': 'sum of values from K is: 2'}
Say i have a list of dictionaries that all have the same keys. and i want to regroup these into several lists such that the values for certain attributes of my choosing are equal. here is an example:
Suppose i have the following list of dictionaries:
[ {'a': 0.0, 'b': 0.2, 'c': 0.1},
{'a': 0.1, 'b': 0.7, 'c': 0.2},
{'a': 0.0, 'b': 0.2, 'c': 0.3},
{'a': 0.1, 'b': 0.7, 'c': 0.4},
{'a': 0.0, 'b': 0.7, 'c': 0.5},
{'a': 0.0, 'b': 0.7, 'c': 0.6}]
and i want to cluster it according the the keys a and b. Then the output would be the following list of list of dictionaries:
[[{'a': 0.0, 'b': 0.2, 'c': 0.1},
{'a': 0.0, 'b': 0.2, 'c': 0.3}]
[{'a': 0.1, 'b': 0.7, 'c': 0.2},
{'a': 0.1, 'b': 0.7, 'c': 0.4}]
[{'a': 0.0, 'b': 0.7, 'c': 0.5},
{'a': 0.0, 'b': 0.7, 'c': 0.6}]]
What is the best way of achieving this?
Sort this firstly, then use itertools.groupby.You may could try this below:
from itertools import groupby
t = [{'a': 0.0, 'b': 0.2, 'c': 0.1},
{'a': 0.1, 'b': 0.7, 'c': 0.2},
{'a': 0.0, 'b': 0.2, 'c': 0.3},
{'a': 0.1, 'b': 0.7, 'c': 0.4},
{'a': 0.0, 'b': 0.7, 'c': 0.5},
{'a': 0.0, 'b': 0.7, 'c': 0.6}]
print([[*j] for i, j in groupby(sorted(t, key=lambda x: (x['a'], x['b'])), key=lambda x: (x['a'], x['b']))])
Result:
[[{'a': 0.0, 'b': 0.2, 'c': 0.1}, {'a': 0.0, 'b': 0.2, 'c': 0.3}], [{'a': 0.0, 'b': 0.7, 'c': 0.5}, {'a': 0.0, 'b': 0.7, 'c': 0.6}], [{'a': 0.1, 'b': 0.7, 'c': 0.2}, {'a': 0.1, 'b': 0.7, 'c': 0.4}]]
If you want to create a function to receive muitlple keys, you could try:
from itertools import groupby
def group_by(*args):
return [[*j] for i, j in groupby(sorted(t, key=itemgetter(*args)), key=itemgetter(*args))]
t = [{'a': 0.0, 'b': 0.2, 'c': 0.1},
{'a': 0.1, 'b': 0.7, 'c': 0.2},
{'a': 0.0, 'b': 0.2, 'c': 0.3},
{'a': 0.1, 'b': 0.7, 'c': 0.4},
{'a': 0.0, 'b': 0.7, 'c': 0.5},
{'a': 0.0, 'b': 0.7, 'c': 0.6}]
print(group_by('a', 'b'))
I have three dictionaries (or more):
A = {'a':1,'b':2,'c':3,'d':4,'e':5}
B = {'b':1,'c':2,'d':3,'e':4,'f':5}
C = {'c':1,'d':2,'e':3,'f':4,'g':5}
How can I get a dictionary of the average values of every key in the three dictionaries?
For example, given the above dictionaries, the output would be:
{'a':1/1, 'b':(2+1)/2, 'c':(3+2+1)/3, 'd':(4+3+2)/3, 'e':(5+4+3)/3, 'f':(5+4)/2, 'g':5/1}
You can use Pandas, like this:
import pandas as pd
df = pd.DataFrame([A,B,C])
answer = dict(df.mean())
print(answer)
I use Counter to solve this problem. Please try the following code :)
from collections import Counter
A = {'a':1,'b':2,'c':3,'d':4,'e':5}
B = {'b':1,'c':2,'d':3,'e':4,'f':5}
C = {'c':1,'d':2,'e':3,'f':4,'g':5}
sums = Counter()
counters = Counter()
for itemset in [A, B, C]:
sums.update(itemset)
counters.update(itemset.keys())
ret = {x: float(sums[x])/counters[x] for x in sums.keys()}
print ret
The easiest way would be to use collections.Counter as explained here, like this:
from collections import Counter
sums = dict(Counter(A) + Counter(B) + Counter(C))
# Which is {'a': 1, 'c': 6, 'b': 3, 'e': 12, 'd': 9, 'g': 5, 'f': 9}
means = {k: sums[k] / float((k in A) + (k in B) + (k in C)) for k in sums}
The result would be:
>>> means
{'a': 1.0, 'b': 1.5, 'c': 2.0, 'd': 3.0, 'e': 4.0, 'f': 4.5, 'g': 5.0}
If you are working in python 2.7 or 3.5 you can use the following:
keys = set(A.keys()+B.keys()+C.keys())
D = {key:(A.get(key,0)+B.get(key,0)+C.get(key,0))/float((key in A)+(key in B)+(key in C)) for key in keys}
which outputs
D
{'a': 1.0, 'c': 2.0, 'b': 1.5, 'e': 4.0, 'd': 3.0, 'g': 5.0, 'f': 4.5}
if you don't want to use any packages. This doesn't work in python 2.6 and below though.
Here's a very general way to do so (i.e. you can easily change to any aggregation function).:
def aggregate_dicts(dicts, operation=lambda x: sum(x) / len(x)):
"""
Aggregate a sequence of dictionaries to a single dictionary using `operation`. `Operation` should
reduce a list of all values with the same key. Keyrs that are not found in one dictionary will
be mapped to `None`, `operation` can then chose how to deal with those.
"""
all_keys = set().union(*[el.keys() for el in dicts])
return {k: operation([dic.get(k, None) for dic in dicts]) for k in all_keys}
example:
dicts_diff_keys = [{'x': 0, 'y': 1}, {'x': 1, 'y': 2}, {'x': 2, 'y': 3, 'c': 4}]
def mean_no_none(l):
l_no_none = [el for el in l if el is not None]
return sum(l_no_none) / len(l_no_none)
aggregate_dicts(dicts_diff_keys, operation= mean_no_none)
#{'x': 1.0, 'c': 4.0, 'y': 2.0}
I'm having a hard time rounding off values in dicts. What I have is a list of dicts like this:
y = [{'a': 80.0, 'b': 0.0786235, 'c': 10.0, 'd': 10.6742903}, {'a': 80.73246, 'b': 0.0, 'c':
10.780323, 'd': 10.0}, {'a': 80.7239, 'b': 0.7823640, 'c': 10.0, 'd': 10.0}, {'a':
80.7802313217234, 'b': 0.0, 'c': 10.0, 'd': 10.9762304}]
I need to round off the values to just 2 decimal places.
When I try the following:
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = ceil(v*100)/100.0
print v
d[k] = v
return
roundingVals_toTwoDeci(y)
s = json.dumps(y)
print s
I get:
0.0
0.0
18.2
0.0
27.3
54.5
0.0
0.0
0.0
[{"a": 0.0, "b": 0.0, "c": 27.300000000000001, "d": 0.0, "e": 54.5, "f": 0.0, "g": 18.199999999999999, "h": 0.0, "i": 0.0}]
I need to make this work with versions 2.4+ and so am not using dict comprehensions.
First, I am having a hard time looping through all the key, values in all the dicts in the original.
Second, this result has just 1 decimal point instead of 2 when it prints inside the function?
Third, why is the 'json.dumps' and then 'print' not showing the values from inside the function?
EDIT:
Working with #Mark Ransom's answer below, I get the desired o/p. However, I have to urlencode the json.dumps value and send it to a URL. At the URL, it decodes the values into all the decimal places. So, for example, if, josn.dumps gives {"a": 9.1}, the URL shows it (after urlencode) as 9.10034254344365. The modified code is as below:
class LessPrecise(float):
def __repr__(self):
return str(self)
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = LessPrecise(round(v, 2))
print v
d[k] = v
roundingVals_toTwoDeci(y)
j = json.dumps(y)
print j
params = urllib.urlencode({'thekey': j})
print json.dumps gives {"a": 9.1}
At the URL after urlencode, it gives 9.1078667322034 instead of 9.1as in the following:
Output:::
100.0
0.0
0.0
0.0
100.0
0.0
0.0
0.0
81.8
0.0
18.2
0.0
90.0
0.0
0.0
10.0
[{"a": 100.0, "b": 0.0, "c": 0.0, "d": 0.0}, {"a": 100.0, "b": 0.0, "c": 0.0, "d": 0.0}, {"a":
81.8, "b": 0.0, "c": 18.2, "d": 0.0}, {"a": 90.0, "b": 0.0, "c": 0.0, "d": 10.0}]
At the URL:
9.100000381469727
The JSON string after json.dumps()
[{"a": 80.0, "b": 0.0, "c": 10.0, "d": 10.0}, {"a": 100.0, "b": 0.0, "c": 0.0, "d": 0.0}, {"a":
80.0, "b": 0.0, "c": 10.0, "d": 10.0}, {"a": 90.0, "b": 0.0, "c": 0.0, "d": 10.0}]
The urlencode string - after decoding at http://meyerweb.com/eric/tools/dencoder/
thekey=[{"a": 80.0, "b": 0.0, "c": 10.0, "d": 10.0}, {"a": 100.0, "b": 0.0, "c": 0.0, "d":
0.0}, {"a": 80.0, "b": 0.0, "c": 10.0, "d": 10.0}, {"a": 90.0, "b": 0.0, "c": 0.0, "d": 10.0}]
At the URL, I get values like 18.200000762939453(this value is from a later script run)
Taking the best bits from a couple of other answers:
class LessPrecise(float):
def __repr__(self):
return str(self)
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = LessPrecise(round(v, 2))
print v
d[k] = v
>>> roundingVals_toTwoDeci(y)
80.0
10.0
0.08
10.67
80.73
10.78
0.0
10.0
80.72
10.0
0.78
10.0
80.78
10.0
0.0
10.98
>>> s=json.dumps(y)
>>> s
'[{"a": 80.0, "c": 10.0, "b": 0.08, "d": 10.67}, {"a": 80.73, "c": 10.78, "b": 0.0, "d": 10.0}, {"a": 80.72, "c": 10.0, "b": 0.78, "d": 10.0}, {"a": 80.78, "c": 10.0, "b": 0.0, "d": 10.98}]'
JSONEncoder uses repr, and repr prints floats with all their available precision. The only possible solutions are to inherit from JSONEncoder and round while actually converting the values to a string (which implies to copy and adapt some code from the json.encoder module), or else wrap the floats into your own type RoundedFloat and register a serializer for that. Also note that repr's behaviour depends on the Python version used.
As often with non-obvious behaviour, the observation during debugging can trick you: print uses str(), and str() rounds at a certain point, unlike repr() which shows the naked ugliness of floating point maths.
The proof is in the code:
>>> class F(float):
... def __str__(self): return "str"
... def __repr__(self): return "repr"
...
...
>>> print F(1)
str
>>> F(1)
repr
>>> repr(1-1e-15)
'0.999999999999999'
>>> str(1-1e-15)
'1.0'
import json
y = [{'a': 80.0, 'b': 0.0786235, 'c': 10.0, 'd': 10.6742903}, {'a': 80.73246, 'b': 0.0, 'c':
10.780323, 'd': 10.0}, {'a': 80.7239, 'b': 0.7823640, 'c': 10.0, 'd': 10.0}, {'a':
80.7802313217234, 'b': 0.0, 'c': 10.0, 'd': 10.9762304}]
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = round(v,2) # <--- round() does exact that.
d[k] = v # <--- You need to put the rounded v back in d
print v
return
roundingVals_toTwoDeci(y)
s = json.dumps(y)
print s
Answering the second part of your question
Try replacing line 5 of your code with:
v = round(v, 2)
This will round the number to two decimal places. Using round, I get
[{'a': 80.0, 'c': 10.0, 'b': 0.08, 'd': 10.67}, {'a': 80.73, 'c': 10.78, 'b': 0.0, 'd': 10.0}, {'a': 80.72, 'c': 10.0, 'b': 0.78, 'd': 10.0}, {'a': 80.78, 'c': 10.0, 'b': 0.0, 'd': 10.98}]
I am using Python 2.7.2. Here's all the code:
from math import ceil
import json
y = [{'a': 80.0, 'b': 0.0786235, 'c': 10.0, 'd': 10.6742903},
{'a': 80.73246, 'b': 0.0, 'c': 10.780323, 'd': 10.0},
{'a': 80.7239, 'b': 0.7823640, 'c': 10.0, 'd': 10.0},
{'a': 80.7802313217234, 'b': 0.0, 'c': 10.0, 'd': 10.9762304}]
def roundingVals_toTwoDeci(y):
for d in y:
for k, v in d.items():
v = round(v, 2)
#print v
d[k] = v
return
roundingVals_toTwoDeci(y)
s = json.dumps(y)
print s
I don't understand what relates to json, but I can propose:
from math import ceil
y = [{'a': 80.0, 'b': 0.0786235, 'c': 10.0, 'd': 10.6742903},
{'a': 80.73246, 'b': 0.0, 'c': 10.780323, 'd': 10.0},
{'a': 80.7239, 'b': 0.7823640, 'c': 10.0, 'd': 10.0},
{'a': 80.7802313217234, 'b': 0.0, 'c': 10.0, 'd': 10.9762304}]
class TwoDec(float):
def __repr__(self):
return "%.2f" % self
def roundingVals_to_TwoDeci(y,ceil=ceil,TwoDec=TwoDec):
for d in y:
for k, v in d.iteritems():
d[k] = TwoDec(ceil(v*100)/100)
roundingVals_to_TwoDeci(y)
for el in y:
print el
result
{'a': 80.00, 'c': 10.00, 'b': 0.08, 'd': 10.68}
{'a': 80.74, 'c': 10.79, 'b': 0.00, 'd': 10.00}
{'a': 80.73, 'c': 10.00, 'b': 0.79, 'd': 10.00}
{'a': 80.79, 'c': 10.00, 'b': 0.00, 'd': 10.98}
I know this question is old, but here is a quick one-liner solution that works at least here in Linux Python 2.7.6 and might be interesting to someone else:
y = [{ x : round(z, 2) for x,z in yi.items()} for yi in y ]
However, this might be inefficient for larger data sets, as it re-generates the list/dict structure.
[[round(d[key],2) for key in d] for d in y]
[{key:round(d[key], 2) for key in d} for d in y]
Round dictionary values one-liner
with d as the dict and here to 2 decimal places
d = {k: round(v, 2) for k, v in d.items()}
Given the subject line Round off dict values to 2 decimals, this is what most will be coming here to find.
dictionary comprehension might be used in a search