Rounding decimals in nested data structures in Python
Question:
I have a program which deals with nested data structures where the underlying type usually ends up being a decimal. e.g.
x={'a':[1.05600000001,2.34581736481,[1.1111111112,9.999990111111]],...}
Is there a simple pythonic way to print such a variable but rounding all floats to (say) 3dp and not assuming a particular configuration of lists and dictionaries? e.g.
{'a':[1.056,2.346,[1.111,10.000],...}
I’m thinking something like
pformat(x,round=3)
or maybe
pformat(x,conversions={'float':lambda x: "%.3g" % x})
except I don’t think they have this kind of functionality. Permanently rounding the underlying data is of course not an option.
Answers:
>>> b = []
>>> x={'a':[1.05600000001,2.34581736481,[1.1111111112,9.999990111111]]}
>>> for i in x.get('a'):
if type(i) == type([]):
for y in i:
print("%0.3f"%(float(y)))
else:
print("%0.3f"%(float(i)))
1.056
2.346
1.111
10.000
The problem Here is we don’t have flatten method in python, since I know it is only 2 level list nesting I have used for loop
.
This will recursively descend dicts, tuples, lists, etc. formatting numbers and leaving other stuff alone.
import collections.abc
import numbers
def pformat(thing, formatfunc):
if isinstance(thing, dict):
return type(thing)((key, pformat(value, formatfunc)) for key, value in thing.items())
if isinstance(thing, collections.abc.Container):
return type(thing)(pformat(value, formatfunc) for value in thing)
if isinstance(thing, numbers.Number):
return formatfunc(thing)
return thing
def formatfloat(thing):
return "%.3g" % float(thing)
x={'a':[1.05600000001,2.34581736481,[8.1111111112,9.999990111111]],
'b':[3.05600000001,4.34581736481,[5.1111111112,6.999990111111]]}
print(pformat(x, formatfloat))
If you want to try and convert everything to a float, you can do
try:
return formatfunc(thing)
except Exception:
return thing
instead of the last three lines of the function.
A simple approach assuming you have lists of floats:
>>> round = lambda l: [float('%.3g' % e) if type(e) is not list else round(e) for e in l]
>>> print({k: round(v) for k, v in x.items()})
{'a': [1.06, 2.35, [1.11, 10.0]]}
I have a program which deals with nested data structures where the underlying type usually ends up being a decimal. e.g.
x={'a':[1.05600000001,2.34581736481,[1.1111111112,9.999990111111]],...}
Is there a simple pythonic way to print such a variable but rounding all floats to (say) 3dp and not assuming a particular configuration of lists and dictionaries? e.g.
{'a':[1.056,2.346,[1.111,10.000],...}
I’m thinking something like
pformat(x,round=3)
or maybe
pformat(x,conversions={'float':lambda x: "%.3g" % x})
except I don’t think they have this kind of functionality. Permanently rounding the underlying data is of course not an option.
>>> b = []
>>> x={'a':[1.05600000001,2.34581736481,[1.1111111112,9.999990111111]]}
>>> for i in x.get('a'):
if type(i) == type([]):
for y in i:
print("%0.3f"%(float(y)))
else:
print("%0.3f"%(float(i)))
1.056
2.346
1.111
10.000
The problem Here is we don’t have flatten method in python, since I know it is only 2 level list nesting I have used for loop
.
This will recursively descend dicts, tuples, lists, etc. formatting numbers and leaving other stuff alone.
import collections.abc
import numbers
def pformat(thing, formatfunc):
if isinstance(thing, dict):
return type(thing)((key, pformat(value, formatfunc)) for key, value in thing.items())
if isinstance(thing, collections.abc.Container):
return type(thing)(pformat(value, formatfunc) for value in thing)
if isinstance(thing, numbers.Number):
return formatfunc(thing)
return thing
def formatfloat(thing):
return "%.3g" % float(thing)
x={'a':[1.05600000001,2.34581736481,[8.1111111112,9.999990111111]],
'b':[3.05600000001,4.34581736481,[5.1111111112,6.999990111111]]}
print(pformat(x, formatfloat))
If you want to try and convert everything to a float, you can do
try:
return formatfunc(thing)
except Exception:
return thing
instead of the last three lines of the function.
A simple approach assuming you have lists of floats:
>>> round = lambda l: [float('%.3g' % e) if type(e) is not list else round(e) for e in l]
>>> print({k: round(v) for k, v in x.items()})
{'a': [1.06, 2.35, [1.11, 10.0]]}