56

I'm looking for a way to convert numbers to string format, dropping any redundant '.0'

The input data is a mix of floats and strings. Desired output:

0 --> '0'

0.0 --> '0'

0.1 --> '0.1'

1.0 --> '1'

I've come up with the following generator expression, but I wonder if there's a faster way:

(str(i).rstrip('.0') if i else '0' for i in lst)

The truth check is there to prevent 0 from becoming an empty string.

EDIT: The more or less acceptable solution I have for now is this:

('%d'%i if i == int(i) else '%s'%i for i in lst)

It just seems strange that there is no elegant way to handle this (fairly straightforward) case in python.

Algorias
  • 3,043
  • 5
  • 22
  • 16

17 Answers17

92

See PEP 3101:

'g' - General format. This prints the number as a fixed-point
      number, unless the number is too large, in which case
      it switches to 'e' exponent notation.

Old style (not preferred):

>>> "%g" % float(10)
'10'

New style:

>>> '{0:g}'.format(float(21))
'21'

New style 3.6+:

>>> f'{float(21):g}'
'21'
Ben Thayer
  • 51
  • 4
erik
  • 1,032
  • 7
  • 8
  • 3
    Thanks. Seems like this does exactly what the OP wanted: elegantly strip superfluous trailing .0 off of integers but don't round, truncate or otherwise munge floating point numbers. And with a bonus of also automagically switching to exponent notation for large numbers! – Noah Sussman Oct 21 '12 at 04:53
  • 3
    @NoahSussman: '%g' may loose precision as shown in [dF's answer from 2008](http://stackoverflow.com/a/385392/4279). – jfs Jun 06 '13 at 02:37
  • 6
    This one doesn't work ```'{0:g}'.format(float(100000.5)) Out[7]: '100000'``` – Yuda Prawira Jul 17 '17 at 18:01
19

rstrip doesn't do what you want it to do, it strips any of the characters you give it and not a suffix:

>>> '30000.0'.rstrip('.0')
'3'

Actually, just '%g' % i will do what you want. EDIT: as Robert pointed out in his comment this won't work for large numbers since it uses the default precision of %g which is 6 significant digits.

Since str(i) uses 12 significant digits, I think this will work:

>>> numbers = [ 0.0, 1.0, 0.1, 123456.7 ]
>>> ['%.12g' % n for n in numbers]
['1', '0', '0.1', '123456.7']
dF.
  • 74,139
  • 30
  • 130
  • 136
  • 1
    %g is not the right way to accomplish this: >>> "%g" % 123456.7 # => '123457'. – Robert Gamble Dec 22 '08 at 03:21
  • So I need to replace rstrip('.0') with rstrip('0').rstrip('.'), which I think will be very slow. There are more pitfalls with the '%g' operator: >>> "%.20g" % 123456.7 # ==> '123456.69999999999709' – Algorias Dec 23 '08 at 02:03
  • @Algorias: not really a pitfall, you're getting the value of the best representation of 123456.7 as a Python double. To get the same as str(x), use "%.12g". – dF. Dec 26 '08 at 18:16
  • last line of demo output should read ['0', '1', '0.1', '123456.7'] - can't edit because edits need to be 6 characters. – David Jan 26 '18 at 15:42
10
>>> x = '1.0'
>>> int(float(x))
1
>>> x = 1
>>> int(float(x))
1
9

So much ugliness out there…

My personal favorite is to convert floats that don't require to be a float (= when they actually are integers) to int, thus removing the, now useless, trailing 0

(int(i) if i.is_integer() else i for i in lst)

Then you can print them normally.

jeromej
  • 10,508
  • 2
  • 43
  • 62
8
def floatstrip(x):
    if x == int(x):
        return str(int(x))
    else:
        return str(x)

Be aware, though, that Python represents 0.1 as an imprecise float, on my system 0.10000000000000001 .

J.T. Hurley
  • 521
  • 9
  • 12
8
(str(i)[-2:] == '.0' and str(i)[:-2] or str(i) for i in ...)
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
7

To print a float that has an integer value as an int:

format = "%d" if f.is_integer() else "%s"
print(format % f)

Example

             0.0 -> 0
             0.1 -> 0.1
            10.0 -> 10
      12345678.9 -> 12345678.9
     123456789.0 -> 123456789
12345678912345.0 -> 12345678912345
12345678912345.6 -> 1.23456789123e+13
  1.000000000001 -> 1.0
jfs
  • 399,953
  • 195
  • 994
  • 1,670
4

If you only care about 1 decimal place of precision (as in your examples), you can just do:

("%.1f" % i).replace(".0", "")

This will convert the number to a string with 1 decimal place and then remove it if it is a zero:

>>> ("%.1f" % 0).replace(".0", "")
'0'
>>> ("%.1f" % 0.0).replace(".0", "")
'0'
>>> ("%.1f" % 0.1).replace(".0", "")
'0.1'
>>> ("%.1f" % 1.0).replace(".0", "")
'1'
>>> ("%.1f" % 3000.0).replace(".0", "")
'3000'
>>> ("%.1f" % 1.0000001).replace(".0", "")
'1'
Robert Gamble
  • 106,424
  • 25
  • 145
  • 137
3
from decimal import Decimal
'%g' % (Decimal(str(x)))
Andy Hume
  • 40,474
  • 10
  • 47
  • 58
2

Using Python's string formatting (use str.format() with Python 3.0):

from decimal import Decimal

def format_number(i):
    return '%g' % (Decimal(str(i)))
Daniel Naab
  • 22,690
  • 8
  • 54
  • 55
2

Following code will convert contents of variable no as it is i.e. 45.60. If you use str the output will be 45.6

no = 45.60

strNo = "%.2f" %no
Ovidiu Dolha
  • 5,335
  • 1
  • 21
  • 30
1
str(x)[-2:] == '.0' and int(x) or x
0
>>> '%g' % 0
'0'
>>> '%g' % 0.0
'0'
>>> '%g' % 0.1
'0.1'
>>> '%g' % 1.0
'1'
A. Coady
  • 54,452
  • 8
  • 34
  • 40
0

Us the 0 prcision and add a period if you want one. EG "%.0f."

>>> print "%.0f."%1.0
1.
>>> 
Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
0

FWIW, with Jinja2 where var = 10.3

{{ var|round|int }} will emit integer 10

round(method='floor') and round(method='ceil') are also available.

So that were var2 = 10.9 {{ var|round(method='floor')|int }} will still emit integer 10

Precision can also be controlled using a keyword argument precision=0 of the round function.

ref: http://jinja.pocoo.org/docs/dev/templates/#round

niklauzg
  • 571
  • 4
  • 6
0

I was dealing with a value from a json dictionary (returned by an API). All the above didnt help me so i constructed by own helper function. It truncates all the trailing zeros.

I Hope it helps someone out there

def remove_zeros(num):
    nums = list(num)
    indexes = (list(reversed(range(len(nums)))))
    for i in indexes:
        if nums[i] == '0':
            del nums[-1]
        else:
            break
    return "".join(nums)

num = "0.000000363000"
print(remove_zeros(num))

prints :

    0.000000363
Edison
  • 870
  • 1
  • 13
  • 28
0

I did this for removing trailing nonsignificant digits past a certain precision.

c = lambda x: float(int(x * 100)/100.)
c(0.1234)
p0licat
  • 45
  • 1
  • 10
  • If you are defining a function (which you are), it's better to use a regular function, not a lambda. This improves the readability of code. – Mahrkeenerh Mar 30 '22 at 18:28