Using Python's Format Specification Mini-Language to specify or automatically determine column widths
-
05-12-2019 - |
Domanda
I have the following example in Python to print a table:
job_IDs = ['13453', '123', '563456'];
memory_used = [30, 150.54, 20.6];
memory_units = ['MB', 'GB', 'MB'];
for i in range(len(job_IDs)):
print "Job {item:15} {value[0]:>6}.{value[1]:<6} {units:3}".format(
item=job_IDs[i]+':', value=memory_used[i].split('.') if '.' in memory_used[i]
else (memory_used[i], '0'), units=memory_units[i])
which results in:
Job 13453: 30 MB Job 123: 150.54 MB Job 563456: 20.6 GB
The vertical alignment is correct for what I need, but the horizontal padding is manually hard-coded in the code, where it says:
"Job {item:15} {value[0]:>6}.{value[1]:<6} {units:3}"
(the "padding parameters" above are 15, 6, 6, 3
)
I would like to:
Ideally, have the padding values determined automatically (i.e. computed from the maximum width of each field) instead of having to hard-code them in the statement above.
In the example above, it would be great to have a snippet that uses the width of the widest entries in
job_IDs
,memory_used
, andmemory_units
and outputs, leaving one space between columns:Job 13453: 30 MB Job 123: 150.54 MB Job 563456: 20.6 GB
Alternatively, I would also interested in a solution that allows me to specify such paddings in variables (in case I want to control the width given to each column).
I am interested in solutions for both problems: with the padding computed automatically, and with the padding specified with variables.
By the way, This question was inspired by this other question: Using Python's Format Specification Mini-Language to align floats
Soluzione
You can nest the arguments to change the integer width like so:
job_IDs = ['13453', '123', '563456'];
memory_used = ['30', '150.54', '20.6'];
memory_units = ['MB', 'GB', 'MB'];
w1=15
w2=6
w3=6
w4=3
for i in range(len(job_IDs)):
v=memory_used[i].split('.') if '.' in memory_used[i] else (memory_used[i], '0')
print "Job {item:{w1}} {value[0]:>{w2}}.{value[1]:<{w3}} {units:{w4}}".format(
item=job_IDs[i]+':', w1=w1, w2=w2,w3=w3,w4=w4, value=v, units=memory_units[i])
So to determine the field width to use, just loop through one time before you print to determine the widest width to use for each applicable embedded width variable.
Like so:
job_IDs = ['13453', '123', '563456'];
memory_used = ['30', '150.54', '20.6'];
memory_units = ['MB', 'GB', 'MB'];
w1=1
w2=1
w3=1
w4=1
for i in range(len(job_IDs)):
v=memory_used[i].split('.') if '.' in memory_used[i] else (memory_used[i], '0')
item=job_IDs[i]+':'
units=memory_units[i]
if len(item)>w1: w1=len(item)
if len(v[0])>w2: w2=len(v[0])
if len(v[1])>w3: w3=len(v[1])
if len(units)>w4: w3=len(units)
for i in range(len(job_IDs)):
v=memory_used[i].split('.') if '.' in memory_used[i] else (memory_used[i], '0')
item=job_IDs[i]+':'
units=memory_units[i]
print "Job {item:{w1}} {value[0]:>{w2}}.{value[1]:<{w3}} {units:{w4}}".format(
item=item,w1=w1, w2=w2,w3=w3,w4=w4, value=v, units=units)
Output:
Job 13453: 30.0 MB
Job 123: 150.54 GB
Job 563456: 20.6 MB