Search code examples
pythonstring-formattingtabular

Formatting output as table


Example input:

[('b', 'c', 4),
('l', 'r', 5),
('i', 'a', 6),
('c', 't', 7),
('a', '$', 8),
('n', '$', 9)]

[0] contains the vertical heading, [1] contains the horizontal heading.

Example output:

  c r a t $ $
b 4  
l   5
i     6
c       7
a         8
n           9

Note: given enough tuples the entire table could be filled :P

How do I format output as a table in Python using [preferably] one line of code?


Solution

  • Here's an answer for your revised question:

    data = [
        ['A','a','1'],
        ['B','b','2'],
        ['C','c','3'],
        ['D','d','4']
    ]
    
    # Desired output:
    #
    #   A B C D
    # a 1
    # b   2
    # c     3
    # d       4
    
    # Check data consists of colname, rowname, value triples
    assert all([3 == len(row) for row in data])
    # Convert all data to strings
    data = [ [str(c) for c in r] for r in data]
    # Check all data is one character wide
    assert all([1 == len(s) for s in r for r in data])
    
    #============================================================================
    # Verbose version
    #============================================================================
    col_names, row_names, values = zip(*data) # Transpose
    
    header_line = '  ' + ' '.join(col_names)
    row_lines = []
    for idx, (row_name, value) in enumerate(zip(row_names,values)):
        # Use '  '*n to get 2n consecutive spaces.
        row_line = row_name + ' ' + '  '*idx + value
        row_lines.append(row_line)
    
    print header_line
    for r in row_lines:
        print (r)
    

    Or, if that's too long for you, try this:

    cs, rs, vs = zip(*data)
    print ('\n'.join(['  '+' '.join(cs)] + [r+' '+'  '*i+v for i,(r,v) in enumerate(zip(rs,vs))]))
    

    Both have the following output:

      A B C D
    a 1
    b   2
    c     3
    d       4
    

    Here's the kernel of what you want (no reader row or header column)

    >>> print('\n'.join([ ''.join([str(i+j+2).rjust(3)
        for i in range(10)]) for j in range(10) ]))
    
      2  3  4  5  6  7  8  9 10 11
      3  4  5  6  7  8  9 10 11 12
      4  5  6  7  8  9 10 11 12 13
      5  6  7  8  9 10 11 12 13 14
      6  7  8  9 10 11 12 13 14 15
      7  8  9 10 11 12 13 14 15 16
      8  9 10 11 12 13 14 15 16 17
      9 10 11 12 13 14 15 16 17 18
     10 11 12 13 14 15 16 17 18 19
     11 12 13 14 15 16 17 18 19 20
    

    It uses a nested list comprehension over i and j to generate the numbers i+j, then str.rjust() to pad all fields to three characters in length, and finally some str.join()s to put all the substrings together.