Reputation: 69
Is there a way to format string output into a table with flexible column width without using any non-standard Python library?
(For example, in the code bellow, longest entry in the 1st column is 'United States' which has 13 characters, so table column width could be just 13[+2] characters instead of fixed width of 20 characters).
There are many good suggestions in answers to this question but they rely on non-standard libraries (Pandas, tabulate, etc.).
Example code using string format specification mini-language:
countries_dict = {'Russia': ['Moscow', 17_098_246], 'Canada': ['Ottawa', 9_984_670], 'China': ['Beijing', 9_596_961], 'United States': ['Washington, D.C.', 9_525_067], 'Brazil': ['Brasília', 8_515_767]}
print('-'*60, '\n| {:<20} | {:<20} | {:<10} |'.format('Country', 'Capital', 'Area'))
print('-'*60)
for k, v in countries_dict.items():
region, area = v
print('| {:<20} | {:<20} | {:<10} |'.format(k, region, area))
print('-'*60)
Current code output:
------------------------------------------------------------
| Country | Capital | Area |
------------------------------------------------------------
| Russia | Moscow | 17098246 |
| Canada | Ottawa | 9984670 |
| China | Beijing | 9596961 |
| United States | Washington, D.C. | 9525067 |
| Brazil | Brasília | 8515767 |
------------------------------------------------------------
Desired code output (column width corresponds to length of the longest value, etc.):
-----------------------------------------------
| Country | Capital | Area |
-----------------------------------------------
| Russia | Moscow | 17098246 |
| Canada | Ottawa | 9984670 |
| China | Beijing | 9596961 |
| United States | Washington, D.C. | 9525067 |
| Brazil | Brasília | 8515767 |
-----------------------------------------------
Upvotes: 1
Views: 1454
Reputation: 261840
There are not many ways. To be able to know the column width, you first need to read your data and to calculate the appropriate width per column.
Only then you can generate the table.
Here is a naive implementation:
def mktable(dic, header=None):
# get max col width
col_widths = list(map(max, zip(*(map(lambda x: len(str(x)), (k,*v))
for k,v in dic.items()))))
# default numeric header if missing
if not header:
header = range(1, len(col_widths)+1)
header_widths = map(lambda x: len(str(x)), header)
# correct column width if headers are longer
col_widths = [max(c,h) for c,h in zip(col_widths, header_widths)]
# create separator line
line = '+%s+' % '+'.join('-'*(w+2) for w in col_widths)
#line = '-' * (sum(col_widths)+(len(col_widths)-1)*3+4)
# create formating string
fmt_str = '| %s |' % ' | '.join(f'{{:<{i}}}' for i in col_widths)
# header
print(line)
print(fmt_str.format(*header))
print(line)
# data
for k, v in countries_dict.items():
print(fmt_str.format(k, *v))
# footer
print(line)
mktable(countries_dict, header=('Country', 'Capital', '----- Area -----'))
output:
+---------------+------------------+------------------+
| Country | Capital | ----- Area ----- |
+---------------+------------------+------------------+
| Russia | Moscow | 17098246 |
| Canada | Ottawa | 9984670 |
| China | Beijing | 9596961 |
| United States | Washington, D.C. | 9525067 |
| Brazil | Brasília | 8515767 |
+---------------+------------------+------------------+
Upvotes: 2