19

I read that I can use Python's Format Specification Mini-Language to have more control over how strings are displayed. However, I am having a hard time figuring out how to use it to display floats aligned on the decimal point.

For example, say I have the following three lists:

job_IDs = ['13453', '123', '563456'];
memory_used = [30, 150.54, 20.6];
memory_units = ['MB', 'GB', 'MB'];

I would like to iterate through these three lists and print

Job 13453:   30      MB
Job 123:    150.54   MB
Job 563456:  20.6    GB

So far I have tried:

for i in range(len(jobIDs)):
    my_str = "{item:15}{value:6} {units:3}".format( 
    item='Job ' + job_IDs[i] + ':' , value=str(memories[i]),units=memory_units[i]);

    print my_str

which prints:

Job 13453:   30      MB
Job 123:     150.54  MB
Job 563456:  20.6    GB

which is almost right, but it does not align the floats around the decimal point. How can I use Python's Format Specification Mini-Language to do it the way I need?

2
  • Your memory_used list is a list of strings. Typically when you want to print floats in a formatted way, you'll use floats. What you have now is a set of strings, and you want the formatting to understand that it should be treated specially. But maybe that's just in the code you posted here? Commented Mar 3, 2012 at 19:27
  • Thanks @MattiasNilsson I have updated my code accordingly. Commented Mar 3, 2012 at 19:37

4 Answers 4

14

This is what you want:

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])

Here is how it works:

This is the main part: value=memory_used[i].split('.') if '.' in memory_used[i] else (memory_used[i], '0'), which means: if there is a decimal point, split the string as the whole and decimal part, or set the decimal part to 0.

Then in the format string: {value[0]:>6}.{value[1]:<6} means, the whole part shifted right, followed by a dot, then the decimal part shifted left.

which prints:

Job 13453:              30.0      MB
Job 123:               150.54     GB
Job 563456:             20.6      MB
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks @xiaomao. I have never seen an if statement where the command to be executed comes before the condition. Do you have any pointers where I can read more about this? Also, what is the role of number 6 in the format string value[0]:<6?
@roseck python's ?:-style syntax is (true) if (condition) else (false). The < in <6 is shift left and 6 is pad to 6 characters.
-1: Actually this doesn't work if memory_used is a list of integers and floats as shown in the OP's question. If it is, a TypeError: argument of type 'int' is not iterable occurs.
12

Here's another implementation based on .split('.') idea. It might be more readable. Split on '.', right-align the left part, left-align the right part:

width = max(map(len, job_IDs)) # width of "job id" field 
for jid, mem, unit in zip(job_IDs, memory_used, memory_units):
  print("Job {jid:{width}}: {part[0]:>3}{part[1]:1}{part[2]:<3} {unit:3}".format(
    jid=jid, width=width, part=str(mem).partition('.'), unit=unit))

Output

Job 13453 :  30     MB 
Job 123   : 150.54  GB 
Job 563456:  20.6   MB 

Comments

4

In case it helps, here's a similar function I use:

def align_decimal(number, left_pad=7, precision=2):
    """Format a number in a way that will align decimal points."""
    outer = '{0:>%i}.{1:<%i}' % (left_pad, precision)
    inner = '{:.%if}' % (precision,)
    return outer.format(*(inner.format(number).split('.')))

It allows a fixed precision after the decimal point.

Comments

1

This does it:

import re

job_IDs = ['13453', '123', '563456']
memory_used = ['30', '150.54', '20.6']
memory_units = ['MB', 'GB', 'MB']

for i in range(len(job_IDs)):
    lh=re.match(r'(\d+)',memory_used[i]).group(1)
    if '.' in memory_used[i]:
        rh=re.match(r'(\d+)\.(\d+)',memory_used[i]).group(2)
        sep='.'
    else:
        rh=''    
        sep=' '


    my_str = "{item:15}{l:>6}{s:1}{r:6} {units:3}".format( 
    item='Job ' + job_IDs[i] + ':' , l=lh,s=sep,r=rh,units=memory_units[i])

    print my_str

To get your precise out put, you need to break the strings on the optional '.'

You could also convert those strings to floats.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.