Let's say I have the following list of dict
t = [{'a': 1.0, 'b': 2.0},
{'a': 3.0, 'b': 4.0},
{'a': 5.0, 'b': 6.0},
{'a': 7.0, 'b': 9.0},
{'a': 9.0, 'b': 0.0}]
Is there an efficient way to extract all the values contained in the dictionaries with a dictionary key value of a?
So far I have come up with the following solution
x = []
for j in t:
x.append(j['a'])
However, I don't like to loop over items, and was looking at a nicer way to achieve this goal.
You can use list comprehension:
t = [{'a': 1.0, 'b': 2.0},
{'a': 3.0, 'b': 4.0},
{'a': 5.0, 'b': 6.0},
{'a': 7.0, 'b': 9.0},
{'a': 9.0, 'b': 0.0}]
new_list = [i["a"] for i in t]
Output:
[1.0, 3.0, 5.0, 7.0, 9.0]
Since this solution uses a for-loop, you can use map instead:
x = list(map(lambda x: x["a"], t))
Output:
[1.0, 3.0, 5.0, 7.0, 9.0]
Performance-wise, you prefer to use list-comprehension solution rather the map one.
>>> timeit('new_list = [i["a"] for i in t]', setup='from __main__ import t', number=10000000)
4.318223718035199
>>> timeit('x = list(map(lambda x: x["a"], t))', setup='from __main__ import t', number=10000000)
16.243124993163093
def temp(p):
return p['a']
>>> timeit('x = list(map(temp, t))', setup='from __main__ import t, temp', number=10000000)
16.048683850689343
There is a slightly difference when using a lambda or a regular function; however, the comprehension execution takes 1/4 of the time.
You can use itemgetter:
from operator import itemgetter
t = [{'a': 1.0, 'b': 2.0},
{'a': 3.0, 'b': 4.0},
{'a': 5.0, 'b': 6.0},
{'a': 7.0, 'b': 9.0},
{'a': 9.0, 'b': 0.0}]
print map(itemgetter('a'), t)
result:
[1.0, 3.0, 5.0, 7.0, 9.0]
Use a list comprehension as suggested in Ajax1234'a answer, or even a generator expression if that would benefit your use case:
t = [{'a': 1.0, 'b': 2.0}, {'a': 3.0, 'b': 4.0}, {'a': 5.0, 'b': 6.0}, {'a': 7.0, 'b': 9.0}, {'a': 9.0, 'b': 0.0}]
x = (item["a"] for item in t)
print(x)
Output:
<generator object <genexpr> at 0x7f0027def550>
The generator has the advantage of not executing or consuming memory until a value is needed. Use next() to take the next item from the generator, or iterate over it with a for loop.
>>> next(x)
1.0
>>> next(x)
3.0
>>> for n in x:
... print(n)
5.0
7.0
9.0
An alternative, albeit a expensive one, is to use pandas:
import pandas as pd
x = pd.DataFrame(t)['a'].tolist()
print(x)
Output:
[1.0, 3.0, 5.0, 7.0, 9.0]
Related
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'}
I want to apply .agg pandas operations to a huge dataset
As an example, I have this code:
from tqdm import tqdm
import pandas as pd
df = pd.DataFrame({"A":[1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0],
"B":[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0],
"C":[1.0, 1.5, 2.0, 2.0, 3.0, 4.0, 5.0, 6.0, 10.0],
"D":[2.0, 5.0, 3.0, 6.0, 4.0, 2.0, 5.0, 1.0, 2.0],
"E":['a', 'a', 'b', 'a', 'b', 'b', 'b', 'a', 'a']})
df2 = df.groupby('B').agg({
'C': 'mean',
'D': 'sum',
'E': lambda x: x.mode()
})
print(df2)
The problem is that my original dataset has 2.000.000 of rows. Transforming it to 130.000 takes some minutes and I would like to see a progress bar
I've tried with tqdm but I don't know how to apply it here. Is there any function similar to .progress_apply() but for .agg()?
This will print the progress as you go, where progress is measured by the fraction of the groups for which statistics are computed. But I'm not sure how much the loop will slow down your computations.
agger = {
'C': 'mean',
'D': 'sum',
'E': lambda x: x.mode()}
gcols = ['B'] # columns defining the groups
groupby = df.groupby(gcols)
ngroups = len(groupby)
gfrac = 0.3 # fraction of groups for which you want to print progress
gfrac_size = max((1, int(ngroups*gfrac)))
groups = []
rows = []
for i,g in enumerate(groupby):
if (i+1)%gfrac_size == 0:
print('{:.0f}% complete'.format(100*(i/ngroups)))
gstats = g[1].agg(agger)
if i==0:
if gstats.ndim==2:
newcols = gstats.columns.tolist()
else:
newcols = gstats.index.tolist()
groups.append(g[0])
rows.append(gstats.values.flat)
df3 = pd.DataFrame(np.vstack(rows), columns=newcols)
if len(gcols) == 1:
df3.index = groups
else:
df3.index = pd.MultiIndex.from_tuples(groups, names=gcols)
df3 = df3.astype(df[newcols].dtypes)
df3
C D E
1.0 1.5 10.0 a
2.0 3.0 12.0 b
3.0 7.0 8.0 a
An alternative (though somewhat hacky) way would be to take advantage of the fact that you use your own function lambda x: x.mode. Since you're already compromising speed using this function, you can write a class that stores information about progress. For example,
import pandas as pd
import numpy as np
df = pd.DataFrame({"A":[1.0, 2.0, 3.0, 1.0, 2.0, 3.0, 1.0, 2.0, 3.0],
"B":[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0],
"C":[1.0, 1.5, 2.0, 2.0, 3.0, 4.0, 5.0, 6.0, 10.0],
"D":[2.0, 5.0, 3.0, 6.0, 4.0, 2.0, 5.0, 1.0, 2.0],
"E":['a', 'a', 'b', 'a', 'b', 'b', 'b', 'a', 'a']})
df2 = df.groupby('B').agg({
'C': 'mean',
'D': 'sum',
'E': lambda x: x.mode()
})
print(df2)
class ModeHack:
def __init__(self, size=5, N=10):
self.ix = 0
self.K = 1
self.size = size
self.N = N
def mode(self, x):
self.ix = self.ix + x.shape[0]
if self.K*self.size <= self.ix:
print('{:.0f}% complete'.format(100*self.ix/self.N))
self.K += 1
return x.mode()
def reset(self):
self.ix = 0
self.K = 1
mymode = ModeHack(size=int(.1*df.shape[0]), N=df.shape[0])
mymode.reset()
agger = {
'C': 'mean',
'D': 'sum',
'E': lambda x: mymode.mode(x)}
df3 = df.groupby('B').agg(agger)
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've implemented Yen's K-shortest path algorithm based on the pseudocode on Wikipedia and a few open-source codes on GitHub (https://gist.github.com/ALenfant/5491853 and https://github.com/Pent00/YenKSP). The only thing I did differently was instead of removing (i, i+1) edges completely, I changed the length of the edge to infinity (which is equivalent to removing the edges in essense I guess?)
I tested my code with a 10-node graph where all nodes are connected to each other. I expected the maximum number of loop-less routes I could generate is above 100 thousands but it turns out that my code could only find up to the 9th shortest route. Is this a limitation of Yen's?
Following is my code and the 10-node sample data.
def yen(nodes, distances, start, end, max_k):
# Dictionary "solspace" stores actual k-shortest paths, the first of which comes from Dijkstra's algorithm.
solspace = {}
potentialsolspace = []
selected = []
# Adding the Dijkstra's shortest path into solspace dictionary
solspace[0] = (dijkstra(nodes, distances, start, end))[0]
# max_k is the specified number of shortest paths you want to find
max_k = max_k
# Looping from k = 1 to k = max_K and the 0 to (size of previous entry of solspace)-1
# Reference: http://en.wikipedia.org/wiki/Yen's_algorithm
for k in range(1, max_k):
#distances = copy.deepcopy(actual_distances)
for i in range(0, (len(solspace[k - 1]) - 1)):
spur_node = solspace[k - 1][i]
spur_node_plus_one = solspace[k - 1][i + 1]
root_path = solspace[k - 1][0:i + 1]
for shortPath in solspace:
path_root_path = (solspace[shortPath])[0:i + 1]
#print(path_root_path)
if root_path == path_root_path and (len(solspace[shortPath]) - 1 > i):
# make each overlapping edges of root path and path_root_path infinity, hence impossible to select
distances[spur_node][spur_node_plus_one] = float('inf')
distances[spur_node_plus_one][spur_node] = float('inf')
# Call Dijkstra function to compute spur path (the shortest path between spur node
# and end ignoring the i,i+1 edge
spur_path_a = dijkstra(nodes, distances, spur_node, end)
spur_path = spur_path_a[0]
# Restore actual dist to distances nested dictionary
# Total path is just the combination of root path & spur path
total_path_tempo = root_path + spur_path
total_path = []
# This removes duplicates nodes but note that this is O(n^2) computing time, not efficient
# Ref: Stack Overflow questions:480214
[total_path.append(item) for item in total_path_tempo if item not in total_path]
print(total_path)
# build up potentialsolspace by adding in total path which are yet found in solspace or Potential
# hence, the use of nested if
if total_path not in solspace.values():
if [total_path, cost_path(total_path, distances)] not in potentialsolspace[:]:
potentialsolspace.append([total_path, cost_path(total_path, distances)])
distances = copy.deepcopy(actual_distances)
# This handles the case of there being no spur paths, or no spur paths left.
# This could happen if the spur paths have already been exhausted (added to A),
# or there are no spur paths at all such as when both the source and sink vertices lie along a "dead end".
if len(potentialsolspace) is 0:
break
wcg = min(potentialsolspace, key=lambda x: x[1])
# remove selected potential shortest path from the potential solspace
potentialsolspace.remove(wcg)
# Attach minimum of potentialSolSpace into solspace dictionary
solspace[k] = wcg[0]
return solspace
Following is the 10-node example arranged in Python nested distionary format. Primary keys are origins while secondary keys are neighbors of primary keys. Values equal the distance between primary key and secondary key.
{'A': {'C': 4.0, 'B': 10.0, 'E': 10.0, 'D': 10.0, 'G': 1.0, 'F': 2.0, 'I': 3.0, 'H': 3.0, 'J': 10.0}, 'C': {'A': 4.0, 'B': 5.0, 'E': 9.0, 'D': 6.0, 'G': 9.0, 'F': 10.0, 'I': 5.0, 'H': 10.0, 'J': 5.0}, 'B': {'A': 2.0, 'C': 10.0, 'E': 8.0, 'D': 1.0, 'G': 8.0, 'F': 4.0, 'I': 2.0, 'H': 2.0, 'J': 6.0}, 'E': {'A': 9.0, 'C': 5.0, 'B': 10.0, 'D': 4.0, 'G': 9.0, 'F': 9.0, 'I': 3.0, 'H': 3.0, 'J': 7.0}, 'D': {'A': 4.0, 'C': 6.0, 'B': 5.0, 'E': 7.0, 'G': 1.0, 'F': 1.0, 'I': 2.0, 'H': 9.0, 'J': 3.0},
'G': {'A': 2.0, 'C': 10.0, 'B': 3.0, 'E': 1.0, 'D': 10.0, 'F': 5.0, 'I': 5.0, 'H': 6.0, 'J': 1.0}, 'F': {'A': 2.0, 'C': 3.0, 'B': 6.0, 'E': 7.0, 'D': 8.0, 'G': 10.0, 'I': 1.0, 'H': 8.0, 'J': 2.0}, 'I': {'A': 1.0, 'C': 1.0, 'B': 2.0, 'E': 1.0, 'D': 6.0, 'G': 7.0, 'F': 1.0, 'H': 6.0, 'J': 2.0},
'H': {'A': 3.0, 'C': 4.0, 'B': 5.0, 'E': 1.0, 'D': 2.0, 'G': 6.0, 'F': 4.0, 'I': 1.0, 'J': 4.0},
'J': {'A': 5.0, 'C': 6.0, 'B': 1.0, 'E': 8.0, 'D': 7.0, 'G': 9.0, 'F': 8.0, 'I': 10.0, 'H': 1.0}}
I think the problem is in this part:
for shortPath in solspace:
path_root_path = (solspace[shortPath])[0:i + 1]
#print(path_root_path)
if root_path == path_root_path and (len(solspace[shortPath]) - 1 > i):
# make each overlapping edges of root path and path_root_path infinity, hence impossible to select
distances[spur_node][spur_node_plus_one] = float('inf')
distances[spur_node_plus_one][spur_node] = float('inf')
# Call Dijkstra function to compute spur path (the shortest path between spur node
# and end ignoring the i,i+1 edge
spur_path_a = dijkstra(nodes, distances, spur_node, end)
Compare this to wikipedia:
for each path p in A:
if rootPath == p.nodes(0, i):
// Remove the links that are part of the previous shortest paths which share the same root path.
remove p.edge(i, i + 1) from Graph;
for each node rootPathNode in rootPath except spurNode:
remove rootPathNode from Graph;
// Calculate the spur path from the spur node to the sink.
spurPath = Dijkstra(Graph, spurNode, sink);
You are meant to loop over paths in A and remove lots of edges from the graph before running Dijkstra.
However, in your code you call Dijkstra from within the loop that should be removing edges, therefore you will only ever run Dijkstra on a graph with a single edge removed and this limits the number of alternative routes you can find.
Try reducing the indent by 2 tab stops on the part that calls Dijkstra.
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