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.6
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'
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.
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
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}]'