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.

1
  • 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. Commented Oct 11, 2014 at 5:29

4 Answers 4

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
          +-------------------------------------+                        
Sign up to request clarification or add additional context in comments.

7 Comments

What is the relevance of square brackets in the join statement? [hdr]
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.
(len(t[0])-2) * This does not seem to be right. How is this calculated?
@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.
@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.
|
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:

1 Comment

How can I achieve this using string formatting and not with the help of this module?
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 |
+-------------------------+

Comments

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.