1

I want to print my output as follows.Although it seems to be easy to be done in the first look, here are the problems. The number of columns can vary, it can be negative numbers, numbers with different digits etc.

So how can I do this perfectly so that the outer border remains intact irrespective of the varying factors inside.

I know I have to use string formatting in python, but not sure how to do it .
1. What logic should I use to print the header +---+?
How to decide the length based on the no of elements inside?
2. How can I print the numbers with fixed width and alignment?

+---------------------------+  
|  3  4  -4   -8  -10  -12  |  
|  5  5   3   -3   -4  -44  |  
| 34 -4 -34  -22   22   22  |
+---------------------------+  

EDIT

I want to achieve this using string formatting and not with the help of a module.

cppcoder
  • 22,227
  • 6
  • 56
  • 81
  • I don't have time for a full answer right now, but the general approach will be: 1. build the inside up a column at a time, realigning the string lengths at each step; 2. build the box around it. – o11c Oct 11 '14 at 05:29

5 Answers5

2

This is what I like about Python - there is always something stopping you from reinventing the wheel.

For your use case, prettytable is a good fit:

import prettytable

l = [
    [3, 4, -4, -8, -10, -12],
    [5, 5, 3, -3, -4, -44],
    [34, -4, -34, -22, 22, 22]
]

table = prettytable.PrettyTable(header=False, vrules=prettytable.FRAME)
for row in l:
    table.add_row(row)

print table

Prints:

+----+----+-----+-----+-----+-----+
| 3  | 4  |  -4 |  -8 | -10 | -12 |
| 5  | 5  |  3  |  -3 |  -4 | -44 |
| 34 | -4 | -34 | -22 |  22 |  22 |
+----+----+-----+-----+-----+-----+

Also check Manually changing table style paragraph of the package documentation page.


There is also texttable, but it is less powerful in terms of tweaking the table look&feel:

import texttable

l = [
    [3, 4, -4, -8, -10, -12],
    [5, 5, 3, -3, -4, -44],
    [34, -4, -34, -22, 22, 22]
]

table = texttable.Texttable()
table.add_rows(l, header=False)

print table.draw()

Prints:

+----+----+-----+-----+-----+-----+
| 3  | 4  | -4  | -8  | -10 | -12 |
+----+----+-----+-----+-----+-----+
| 5  | 5  | 3   | -3  | -4  | -44 |
+----+----+-----+-----+-----+-----+
| 34 | -4 | -34 | -22 | 22  | 22  |
+----+----+-----+-----+-----+-----+

Another option is tabulate which introduces a set of pre-defined table formats, e.g. "grid":

from tabulate import tabulate

l = [
    [3, 4, -4, -8, -10, -12],
    [5, 5, 3, -3, -4, -44],
    [34, -4, -34, -22, 22, 22]
]

table = tabulate(l, tablefmt="grid")
print table

Prints:

+----+----+-----+-----+-----+-----+
|  3 |  4 |  -4 |  -8 | -10 | -12 |
+----+----+-----+-----+-----+-----+
|  5 |  5 |   3 |  -3 |  -4 | -44 |
+----+----+-----+-----+-----+-----+
| 34 | -4 | -34 | -22 |  22 |  22 |
+----+----+-----+-----+-----+-----+

Also see relevant threads:

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
2

Using no packages and no modules:

nums= [[  3, 4, -4,  -8, -10, -12,], [  5, 5,  3,  -3,  -4, -44,], [ 34,-4,-34, -22,  22,  22]]

t = ['|' + ''.join('%4i' % i for i in row) + ' |' for row in nums]
hdr = '+' +  (len(t[0])-2) * '-' + '+'
print '\n'.join( [hdr] + t + [hdr] )

This produces the output:

+-------------------------+
|   3   4  -4  -8 -10 -12 |
|   5   5   3  -3  -4 -44 |
|  34  -4 -34 -22  22  22 |
+-------------------------+

How it works:

  • t = ['|' + ''.join('%4i' % i for i in row) + ' |' for row in nums]

    t contains everything except the top and bottom rows. At its heart, the numbers are formatted as fixed width and aligned according to specification %4i. %4i means allow four spaces, format as an integer, and align right. Many other specifications are possible. If you wanted, for example, to 5-space wide integers aligned left, use %-5i.

  • hdr = '+' + (len(t[0])-2) * '-' + '+'

    Now that the interior rows are saved in t, we can assemble the header and trailer lines. These lines begin and end with a plus sign. The rest are filled with -.

  • print '\n'.join( [hdr] + t + [hdr] )

    This adds the hdr string to the beginning and end of the list of rows t and then joins all the rows together with newline characters to make the final table.

More complex example

Let's format the above table but add the min, max, mean, and standard deviation for each row at the end of each row.

def mmmsd(row):
    mean=sum(row)/len(row)
    stddev = ( sum( (x-mean)**2.0 for x in row ) / float(len(row)) )**0.5
    return '%6i%6i%6.2f%6.2f' % (min(row), max(row), mean, stddev)

nums= [[  3, 4, -4,  -8, -10, -12,], [  5, 5,  3,  -3,  -4, -44,], [ 34,-4,-34, -22,  22,  22]]

stats = [mmmsd(row) for row in nums]
t = [10*' ' + '|' + ''.join('%6i' % i for i in row) + ' |' + st for row, st in zip(nums, stats)]
hdr = 10*' ' + '+' +  (len(t[0])-12 - len(stats[0])) * '-' + '+' + len(stats[0]) * ' '
print '\n'.join( [hdr] + t + [hdr] )

This produces the result:

          +-------------------------------------+
          |     3     4    -4    -8   -10   -12 |   -12     4 -5.00  6.18
          |     5     5     3    -3    -4   -44 |   -44     5 -7.00 17.23
          |    34    -4   -34   -22    22    22 |   -34    34  3.00 24.92
          +-------------------------------------+                        
John1024
  • 109,961
  • 14
  • 137
  • 171
  • 1
    What is the relevance of square brackets in the `join` statement? `[hdr]` – cppcoder Oct 11 '14 at 06:20
  • 1
    `hdr` is a string. `t` is a list. To add them together, we need to convert `hdr` to a list. That is what the square brackets do in `[hdr]`. The result of `[hdr] + t + [hdr]` is a new list whose first and last elements are hdr. – John1024 Oct 11 '14 at 06:33
  • `(len(t[0])-2) *` This does not seem to be right. How is this calculated? – cppcoder Oct 11 '14 at 06:46
  • 1
    @cppcoder `len(t[0])` is the number of columns of the first row of `t` which is the same as the number of columns in the final output. For the header, the first and last characters are `+`. Therefore, we want `(len(t[0])-2)` dashes in between those two plus signs. – John1024 Oct 11 '14 at 06:49
  • That means you are calculating one dash per column. But one column requires at least 3 dashes to cover a 3 digit number. No? – cppcoder Oct 11 '14 at 06:55
  • 1
    @cppcoder We started with numbers in `nums`. The rows in `t` are strings, not numbers. They are already fully formatted and include the leading and trailing vertical bars. Hence, `len(t[0])` is the total number of columns of the character output and `(len(t[0])-2)` is the total number of dashes needed. – John1024 Oct 11 '14 at 07:00
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/62863/discussion-between-cppcoder-and-john1024). – cppcoder Oct 11 '14 at 07:06
0

1 first you have to calc the numbers before print the -

2 format print in python

AlexWei
  • 1,093
  • 2
  • 8
  • 32
0

This variation calculates the maximum column width required before printing, so all columns are of the same width, but you don't need to hard-code the width into your print format string. It uses the handy but relatively obscure * format parameter to determine the field width.

>>> nums=[[3, 4, -4, -8, -10, -12], [5, 5, 3, -3, -4, -44], [34, -4, -34, -22, 22, 22]]
>>> width=max(len(str(i)) for i in sum(nums,[]))
>>> body='\n'.join(['| ' + ' '.join(['%*d' % (width, i) for i in row]) + ' |' for row in nums])
>>> cols=len(nums[0]); hdr='+' + (cols * (width + 1) + 1) * '-' + '+'
>>> print '%s\n%s\n%s' % (hdr, body, hdr)
+-------------------------+
|   3   4  -4  -8 -10 -12 |
|   5   5   3  -3  -4 -44 |
|  34  -4 -34 -22  22  22 |
+-------------------------+
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
0

Another variaton is to use the str.format() method.

def extract_items_from_nested_list (_list):
    '''
    Generator extracts items of nested lists
    '''
    for item in _list: 
        if isinstance(item, list):
            yield from extract_items_from_nested_list(item)
        else:
            yield item

def _evaluate_column_width (nested_int_list, extra_space=1):
    '''
    Helper function to evaluate required width of the columns
    '''
    flat_value_list = list(extract_items_from_nested_list(nested_int_list))
    # evaluate size of string length for every item
    string_size_list = [len(str(item)) for item in flat_value_list]
    # evaluate max size and add some extra space
    return max(string_size_list) + extra_space

def render_table(nums):
    column_width = _evaluate_column_width(nums)
    # using str.format()
    format_string = "{:" + str(column_width) + "d}"
    t = ['|' + ''.join(format_string.format(value) for value in row) + ' |' for row in nums]
    hdr = '+' + (len(t[0]) - 2) * '-' + '+'
    print('\n'.join([hdr] + t + [hdr]))

if __name__ == '__main__':
    nums= [[  3, 4, -4,  -8, -10, -12], [  5, 5,  3,  -3,  -4, -44,], [ 34,-4,-34, -22,  22,  22]]
    render_table(nums)
Volker
  • 453
  • 1
  • 4
  • 6