5
\$\begingroup\$

A challenge in the beginner book "Automate the boring stuff":

#! Python3

# Table printer
# Takes a list of lists of strings and displays in right-justified table
# assumption is inner lists contain same number items
# each inner list must be printed as a column

the_list = [["a", "bbbbbbbbb", "tttt"],
            ["d", "eeee", "ggggggggggg"],
            ["g", "hhh", "kkkkkkkkkkkkkkkk"]]

def print_table(a_list):
    """
    Prints a 2d list as a right justified table where each column represents
    an inner list 
    """
    rows = len(the_list[0])
    columns = len(the_list)
    column_widths = [0 for i in range(columns)]
    # find longest string in each inner lists(or column)
    for i in range(len(column_widths)):
        longest = 0
        for item in a_list[i]:
            if len(item) > longest:
                longest = len(item)
        column_widths[i] = longest

    # store strings in list
    print_row = ["" for i in range(rows)]
    # iterate over lists to produce strings with correct formatting
    for a in range(rows):
        for i in range(columns):
            print_row[a] = print_row[a] + a_list[i][a].rjust(column_widths[i]
                                                             + 4)
    for item in print_row:
        print(item)

print_table(the_list)
\$\endgroup\$
2
  • \$\begingroup\$ Can you rephrase your post to reflect the review you are looking for. OK? isn't enough to reflect what you are looking for. \$\endgroup\$
    – Tolani
    Commented Oct 10, 2016 at 15:03
  • 2
    \$\begingroup\$ Well I've been chastised in the past for doing just that tbh :/ Any suggested improvements at all are welcome. Many times after I post here, someone arrives and writes a script half the length to perform the same task. In addition, I'm assuming some other beginners may stumble across this in the future, this had me strangely frustrated for a while. \$\endgroup\$ Commented Oct 10, 2016 at 15:17

1 Answer 1

6
\$\begingroup\$

The way that you find rows and columns is good. You can't iterate through the lists so this approach is good. However using them for your comprehensions is bad.

The name a_list is not descriptive, and quite poor. table whilst generic is much better.

Your comprehensions and loops are actually rather poor. Your comprehensions are used as if you are initialize an array in say C. But this is Python, not C.

You should also use the builtins. The way you find the longest in a list can be changed to use max instead. And if you use a comprehension to change all the strings to their length then you could make column_widths a comprehension.

column_widths = [max(len(cell) for cell in column) for column in table]

Your print row is also quite strange. Instead of print_row[a] = print_row[a] + you should use print_row[a] += but this can be done in a list comprehension too. As you're joining the items by nothing you can 'wrap' the comprehension with ''.join. And the comprehension would just be the indexing the table and justifying you're already doing. This can result in:

print_row = ["" for i in range(rows)]
for row in range(rows):
    print_row[row] = ''.join(
        table[col][row].rjust(column_widths[col])
        for col in range(columns)
    )

for item in print_row:
    print(item)

From this you should notice that there is not much point in adding to a list, if you're just going to print it later anyway. And so you can merge these two loops together and remove the print_row comprehension.

Also I'd change the rjust call to not add 4 spaces, as that indents the table, which looks kinda ugly. And you can add a space between each column by using ' '.join instead. This can result in the function:

def print_table(table):
    rows, columns = len(table[0]), len(table)

    column_widths = [max(len(cell) for cell in column) for column in table]
    for row in range(rows):
        print(' '.join(table[col][row].rjust(column_widths[col]) for col in range(columns)))
\$\endgroup\$
4
  • \$\begingroup\$ Since the table parameter is in a column-major arrangement, you should rename the dummy variables: column_widths = [max(len(cell) for cell in column) for column in table]. \$\endgroup\$ Commented Oct 10, 2016 at 17:42
  • \$\begingroup\$ Thanks so much, I appreciate that! I've had a close look at list comprehensions this morning (which also led to me sets) after reading your post. Interesting stuff. \$\endgroup\$ Commented Oct 11, 2016 at 7:58
  • \$\begingroup\$ How would you make the 1st column R-justified and the remaining L-justified? It seem that the list comprehension make that hard to accomplish, in this case. \$\endgroup\$
    – not2qubit
    Commented Nov 12, 2018 at 14:58
  • \$\begingroup\$ @not2qubit I'd use str.format, if you ask another - on-topic - question then I could show you. \$\endgroup\$
    – Peilonrayz
    Commented Nov 12, 2018 at 15:06

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.