13

I have data (numbers) saved in the following format (example):

234 127 34 23 45567  
23 12 4 4 45  
23456 2 1 444 567  
...

Is there any python-way method to line up the numbers and get them as

  234  127  34   23  45567  
   23   12   4    4     45  
23456    2   1  444    567 

(I cannot predict the column size).

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
pb100
  • 736
  • 3
  • 11
  • 20
  • Is it unfeasible to iterate once through the data to determine maximum column size? – teukkam Sep 10 '10 at 17:34
  • possible duplicate of [Python: pretty-printing ascii tables?](http://stackoverflow.com/questions/5909873/python-pretty-printing-ascii-tables) – ecatmur Aug 08 '12 at 12:42
  • Also possible duplicate of [_How do I print parameters of multiple Python objects in table form?_](http://stackoverflow.com/questions/12503655/how-do-i-print-parameters-of-multiple-python-objects-in-table-form) – martineau Feb 10 '14 at 10:37
  • look at the `.rjust(n)` method - left padding characters perhaps? – Ross Sep 10 '10 at 14:07
  • Possible duplicate of [Printing Lists as Tabular Data](http://stackoverflow.com/questions/9535954/printing-lists-as-tabular-data) – Ciro Santilli OurBigBook.com Apr 29 '17 at 10:18

7 Answers7

15

Here is a simple, self-contained example that shows how to format variable column widths:

data = '''\
234 127 34 23 45567
23 12 4 4 45
23456 2 1 444 567'''

# Split input data by row and then on spaces
rows = [ line.strip().split(' ') for line in data.split('\n') ]

# Reorganize data by columns
cols = zip(*rows)

# Compute column widths by taking maximum length of values per column
col_widths = [ max(len(value) for value in col) for col in cols ]

# Create a suitable format string
format = ' '.join(['%%%ds' % width for width in col_widths ])

# Print each row using the computed format
for row in rows:
  print format % tuple(row)

which outputs:

  234 127 34  23 45567
   23  12  4   4    45
23456   2  1 444   567
Kevin Jacobs
  • 616
  • 3
  • 7
  • 1
    Thanks for this. FWIW I made the columns left-justified by generating the format string with `'%%-%ds'` – Matt S. Apr 18 '14 at 22:55
  • 1
    Here's the relevant part with the new-style formats, left-aligned: fmt = ' '.join(['{{:<{}}}'.format(width) for width in col_widths]) for row in rows: print fmt.format(*row) – mueslo May 27 '15 at 14:20
10

You need some way of finding the column size, maybe by reading all the data and finding the maximum width.

>>> line='234 127 34 23 45567'
>>> line.split()
['234', '127', '34', '23', '45567']
>>> max(map(len, line.split()))
5

Repeat over all lines, to find column size (e.g., 5). Constructing a formatted line with percent formatting is straightforward.

>>> colsize = 5
>>> ' '.join(('%*s' % (colsize, i) for i in line.split()))
'  234   127    34    23 45567'
>>> 
gimel
  • 83,368
  • 10
  • 76
  • 104
4
#!/usr/bin/env python

class ALIGN:
    LEFT, RIGHT = '-', ''

class Column(list):
    def __init__(self, name, data, align=ALIGN.RIGHT):
        list.__init__(self, data)
        self.name = name
        width = max(len(str(x)) for x in data + [name])
        self.format = ' %%%s%ds ' % (align, width)

class Table:
    def __init__(self, *columns):
        self.columns = columns
        self.length = max(len(x) for x in columns)
    def get_row(self, i=None):
        for x in self.columns:
            if i is None:
                yield x.format % x.name
            else:
                yield x.format % x[i]
    def get_rows(self):
        yield ' '.join(self.get_row(None))
        for i in range(0, self.length):
            yield ' '.join(self.get_row(i))

    def __str__(self):
        return '\n'.join(self.get_rows())   

For your example:

if __name__ == '__main__':
    print Table(
        Column("", [234, 32, 23456]),
        Column("", [127, 12, 2]),
        Column("", [34, 4, 1]),
        Column("", [23, 4, 444]),
        Column("", [45567, 45, 567])
    )

It will yield:

   234   127   34    23   45567 
    32    12    4     4      45 
 23456     2    1   444     567 

Adapted from http://code.activestate.com/recipes/577202-render-tables-for-text-interface/

miku
  • 181,842
  • 47
  • 306
  • 310
2
>>> rows = """234 127 34 23 45567
... 23 12 4 4 45
... 23456 2 1 444 567"""

first convert the rows into a 2d array (list of lists)

>>> arr=[x.split() for x in rows.split("\n")]

now compute the space each field will need to fit into

>>> widths = [max(map(len,(f[i] for f in tab))) for i in range(len(arr[0]))]

and pad each element to fit into that space

>>> [[k.rjust(widths[i]) for i,k in enumerate(j)] for j in arr]
[['  234', '127', '34', ' 23', '45567'], ['   23', ' 12', ' 4', '  4', '   45'], ['23456', '  2', ' 1', '444', '  567']]

finally join the array back into a string

>>> print "\n".join("  ".join(k.rjust(widths[i]) for i,k in enumerate(j)) for j in arr)
  234  127  34   23  45567
   23   12   4    4     45
23456    2   1  444    567
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
1

Integer in front of the d is what column the integers will start after the previous number so you can line them up however you see fit

print("{0:4d} {1:4d} {2:4d} {3:4d} {4:4d}".format(234, 127, 34, 23, 45567))

repeat as necessary

macfij
  • 3,093
  • 1
  • 19
  • 24
Kody
  • 11
  • 1
1

Try this nice well documented example http://code.activestate.com/recipes/267662-table-indentation/

Rahul
  • 1,866
  • 17
  • 32
0

Kevin Jacobs's answer modified to allow a variable number of integers on each row:

def align(data, delimiter = '\t', is_left_align = True):
  rows = [row.strip().split(delimiter) for row in data.split('\n')]
  cols = map(lambda *row: [str(field) or '' for field in row], *rows)
  widths = [max(len(field) for field in col) for col in cols]
  format = ['%%%s%ds' % ('-' if is_left_align else '', width) for width in widths]
  return '\n'.join([delimiter.join(format[:len(row)]) % tuple(row) for row in rows])

data = '''\
234 127 34 23 45567
23 12 4 4 45
23456 2 1 444 567'''
print(align(data, ' ', False))
Gnubie
  • 2,587
  • 4
  • 25
  • 38