Code Review Asked by Phillip C on October 27, 2021
I’m working through Chapter 6 in "Automate the Boring Stuff, 2nd Edition." Here is the chapter project at the end.
Write a function named printTable() that takes a list of lists of strings and displays it in a well-organized table with each column right-justified. Assume that all the inner lists will contain the same number of strings. For example, the value could look like this:
tableData = [['apples', 'oranges', 'cherries', 'banana'],
['Alice', 'Bob', 'Carol', 'David'],
['dogs', 'cats', 'moose', 'goose']]
Your printTable() function would print the following:
apples Alice dogs
oranges Bob cats
cherries Carol moose
banana David goose
The first time I tackled this project, here was what I came up with:
#! python3
# Displays a table with each column right-justified.
table_data = [["apples", "oranges", "cherries", "bananas"],
["Alice", "Bob", "Carol", "David"],
["dogs", "cats", "moose", "goose"]]
def print_table(table_data):
# Create a new list of 3 "0" values: one for each list in table_data
col_widths = [0] * len(table_data)
# Search for the longest string in each list of table_data
# and put the numbers of characters in the new list
for y in range(len(table_data)):
for x in table_data[y]:
if col_widths[y] < len(x):
col_widths[y] = len(x)
# Rotate and print the list of lists
for x in range(len(table_data[0])):
for y in range(len(table_data)):
print(table_data[y][x].rjust(col_widths[y]), end=" ")
print()
print_table(table_data)
The second time, I found out about the MAX method after several searches on Google. Here is what I came up with using the MAX method.
#! python3
# Displays a table with each column right-justified
table_data = [["apples", "oranges", "cherries", "bananas"],
["Alice", "Bob", "Carol", "David"],
["dogs", "cats", "moose", "goose"]]
def print_table(table_data):
# Create a new list of 3 "0" values: one for each list in table_data
col_widths = [0] * len(table_data)
# Search for longest string in each list of table_data
# and put the numbers of characters in new list
for y in range(len(table_data)):
x = max(table_data[y], key=len)
if col_widths[y] < len(x):
col_widths[y] = len(x)
# Rotate and print the lists of lists
for x in range(len(table_data[0])):
for y in range(len(table_data)):
print(table_data[y][x].rjust(col_widths[y]), end=" ")
print()
print_table(table_data)
Any feedback would be greatly appreciated. Thanks!
First, get the width of each column. This can be easily done with a list comprehension:
width = [max(len(item) for item in column) for column in tableData]
Where max(len(item) for item in column)
gets the maximum length of an item in the column. And the [ ... for column in tableData]
repeats it for each column.
Then build a format string to format each row in the desired format.
fmt = ' '.join(f"{{:>{w}}}" for w in width)
Where f"{{:>{w}}}"
is a f-string expression. Double braces get replaced by single braces and {w}
gets replace by the value of w. For example, with w = 8
the f-string evaluates to "{:>8}"
. This corresponds to a format to right justify (the >
) in a field of width 8. A separate string is created for each column, which are joined by a space (' '). In the example table, width = [8, 5, 5], so fmt is "{:>8} {:>5} {:>5}"
.
Lastly, print each row of the table using the format.
for row in zip(*tableData):
print(fmt.format(*row))
Where for row in zip(*tableData)
is a Python idiom for iterating over the rows when you have a list of columns.
Putting it together:
def print_table(table_data):
width = [max(len(item) for item in col) for col in tableData]
fmt = ' '.join(f"{{:>{w}}}" for w in width)
for row in zip(*tableData):
print(fmt.format(*row))
Answered by RootTwo on October 27, 2021
You can transpose the given list of lists using a single line:
zip(*table_data)
That's it. Now, to find the longest word in each column, it would be another 1-liner:
map(len, [max(_, key=len) for _ in table_data])
You are calculating len(table_data)
a lot of times. Better to store it as a variable? Although, another comprehension could be:
for row in zip(*table_data):
for index, cell in enumerate(row):
print(cell.rjust(col_width[index]), end=" ")
You whole function now becomes:
from typing import List
def print_table(table_data: List):
col_width = list(map(len, [max(_, key=len) for _ in table_data]))
for row in zip(*table_data):
for index, cell in enumerate(row):
print(cell.rjust(col_width[index]), end=" ")
print()
Answered by hjpotter92 on October 27, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP