Formatting Numbers So They Align On Decimal Point Formatting Numbers So They Align On Decimal Point python python

Formatting Numbers So They Align On Decimal Point


If you know the precision (digits after the decimal point) that you need, and you don't mind having some trailing zeros when whole numbers are used, you could use the new f-string in Python 3.6 (PEP498):

numbers = [4.8, 49.723, 456.781, -72.18, 5, 13]for number in numbers:    print(f'{number:9.4f}')

Prints:

  4.8000 49.7230456.7810-72.1800  5.0000 13.0000


I don't think there's a straight-forward way to do it, since you need to know the position of the decimal point in all the numbers before you start printing them. (I just had a look at Caramiriel's link, and some of the links from that page, but I couldn't find anything particularly applicable to this case).

So it looks like you have to do some string-based inspection & manipulation of the numbers in the list. Eg,

def dot_aligned(seq):    snums = [str(n) for n in seq]    dots = [s.find('.') for s in snums]    m = max(dots)    return [' '*(m - d) + s for s, d in zip(snums, dots)]nums = [4.8, 49.723, 456.781, -72.18]for s in dot_aligned(nums):    print(s)

output

  4.8 49.723456.781-72.18

If you want to handle a list of floats with some plain ints mixed in, then this approach gets a bit messier.

def dot_aligned(seq):    snums = [str(n) for n in seq]    dots = []    for s in snums:        p = s.find('.')        if p == -1:            p = len(s)        dots.append(p)    m = max(dots)    return [' '*(m - d) + s for s, d in zip(snums, dots)]nums = [4.8, 49.723, 456.781, -72.18, 5, 13]for s in dot_aligned(nums):    print(s)    

output

  4.8 49.723456.781-72.18  5 13

As Mark Ransom notes in the comments, we can simplify handling ints by using .split:

def dot_aligned(seq):    snums = [str(n) for n in seq]    dots = [len(s.split('.', 1)[0]) for s in snums]    m = max(dots)    return [' '*(m - d) + s for s, d in zip(snums, dots)]

Masher mentions in a comment that it can be useful to add padding on the right so that the numbers can be printed in aligned columns. However, we don't need to compute the size of that padding for each string, we can use the str.ljust method.

def dot_aligned(seq):    snums = [str(n) for n in seq]    dots = [len(s.split('.', 1)[0]) for s in snums]    m = max(dots)    left_pad = [' '*(m - d) + s for s, d in zip(snums, dots)]    ms = max(map(len, left_pad))    return [s.ljust(ms) for s in left_pad]nums = [4.8, 49.723, 456.781, -72.18, 5, 13, 1.2345] * 3cols = 4# Get number of cells in the output grid, using ceiling divisionsize = len(nums) // -cols * -colspadded = dot_aligned(nums)for i in range(0, size, cols):    print(*padded[i:i+cols])

output

  4.8     49.723  456.781  -72.18    5       13        1.2345   4.8    49.723  456.781  -72.18     5      13        1.2345   4.8     49.723 456.781  -72.18     5       13       1.2345


The easy way to do it, if you don't mind trailing zeroes is this:

numbers = [4.8,49.723,456.781,-72.18,5,13]for f in numbers:    print('{:>7.3f}'.format(f))

Which prints:

   4.800  49.723 456.781 -72.180   5.000  13.000

If you want to get rid of the trailing zeroes, one thing you can do is use the re.sub method from the Regular Expressions module:

import renumbers = [4.8,49.723,456.781,-72.18,5,13]for f in numbers:    print(re.sub(r'\.?0+$','','{:>7.3f}'.format(f)))

Which prints:

  4.8 49.723456.781-72.18  5 13

However, this will give you columns of different widths. The only difference is spaces, so you can't see it, but if you were doing it as part of a table, it would look like this:

import renumbers = [4.8,49.723,456.781,-72.18,5,13]for f in numbers:    print(re.sub(r'\.?0+$','','{:>7.3f}'.format(f)),'|')

Prints:

  4.8 | 49.723 |456.781 |-72.18 |  5 | 13 |

To avoid this, if you want to get really fancy you can do this:

import renumbers = [4.8,49.723,456.781,-72.18,5,13]for f in numbers:    print(re.sub(r'\.?0+$',lambda match: ' '*(match.end()-match.start()),'{:>7.3f}'.format(f)),'|')

Which prints:

  4.8   | 49.723 |456.781 |-72.18  |  5     | 13     |

Hope this helps!