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)
-
\$\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– Tolani2016年10月10日 15:03:41 +00:00Commented 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\$Michael Johnson– Michael Johnson2016年10月10日 15:17:47 +00:00Commented Oct 10, 2016 at 15:17
2 Answers 2
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)))
-
\$\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\$200_success– 200_success2016年10月10日 17:42:25 +00:00Commented 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\$Michael Johnson– Michael Johnson2016年10月11日 07:58:52 +00:00Commented 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– not2qubit2018年11月12日 14:58:03 +00:00Commented 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\$2018年11月12日 15:06:38 +00:00Commented Nov 12, 2018 at 15:06
Wrong variable
def print_table(a_list):
"""..."""
rows = len(the_list[0])
columns = len(the_list)
...
You’re passing a_list
in a function parameter, but use the global variable the_list
in the body of the function. This will result in a bug if you attempt to print more than one, differently dimensioned tables.
Documentation
"""
Prints a 2d list as a right justified table where each column represents
an inner list
"""
I’m pretty sure each inner list represents a column, not the other way around.
Simplifications
columns = len(the_list)
column_widths = [0 for i in range(columns)]
for i in range(len(column_widths)):
Initializing a list with a number of zeros could be done simpler as:
column_widths = [0] * columns
column_widths
contains columns
0
’s. We know this because we just constructed it as such. Therefore, len(column_widths)
must evaluate to columns
, so range(len(column_widths))
could be simply range(columns)
!
Explore related questions
See similar questions with these tags.