markzzzz
markzzzz

Reputation: 99

Use string format create a 2D list

Assume input 'table' is a list of lists of strings, the goal is create and return a formatted
string representing the 2D table.

Here is what I got:

def show_table(table):
    new_string = '' 
    for i in table: 
        for j in range(len(i)):
            line = i[j]
            new_string += '| {} '.format(i[j])
        new_string += '|\n'

    return new_string

My code works in some cases when rows' spacing is equal. For example:

input: [['A','BB'],['C','DD']]
output: '| A | BB |\n| C | DD |\n'
print:| A | BB |
      | C | DD |

However, when the rows are not similar like:

input: [['10','2','300'],['4000','50','60'],['7','800','90000']]

It causes my output to differ:

Right_output: '| 10   | 2   | 300   |\n| 4000 | 50  | 60    |\n| 7    | 800 | 90000 |\n'
my_output: '| 10 | 2 | 300 |\n| 4000 | 50 | 60 |\n| 7 | 800 | 90000 |\n'

And the right output should properly looks like:

| 10   | 2   | 300   |
| 4000 | 50  | 60    |
| 7    | 800 | 90000 |

my output:

| 10 | 2 | 300 |
| 4000 | 50 | 60 |
| 7 | 800 | 90000 |

Where do I need to modifier my code to make my print out match the right output? I guess it's something about the max width of columns?

Upvotes: 2

Views: 701

Answers (2)

Eugene Yarmash
Eugene Yarmash

Reputation: 149756

The syntax for padding a string with str.format() (aligning to the left) is like this:

>>> '{:10}'.format('test')
'test      '

You need to precalculate the widths of columns before printing the table. This produces the right output:

def show_table(table):
    new_string = ''

    widths = [max([len(col) for col in cols]) for cols in zip(*table)]

    for i in table:
        for j in range(len(i)):
            new_string += '| {:{}} '.format(i[j], widths[j])
        new_string += '|\n'

    return new_string

Upvotes: 1

dron22
dron22

Reputation: 1233

To get your desired output, I integrated the maximum width of the table elements into your function:

def show_table(table):
    max_widths = map(max, map(lambda x: map(len, x), zip(*table)))
    new_string = '' 
    for i in table: 
        for j in range(len(i)):
            line = i[j]
            line = line + ' '*(max_widths[j]-len(line)) 
            new_string += '| {} '.format(line)
        new_string += '|\n'

    return new_string

To explain the max_widths line...

max_widths = map(max, map(lambda x: map(len, x), zip(*table)))

...it could be done in 3 steps:

  1. Transpose rows and columns of the table

    transposed = zip(*table)
    
  2. Get the lengths of all strings to allow comparison

    lengths = map(lambda x: map(len, x), transposed)
    
  3. Get the maximum length per column

    max_widths = map(max, lengths)
    

Upvotes: 1

Related Questions