Prev - #32 Convert Strings To Integers | Table of Contents | Next - #34 Uppercase Letters

commaFormat(12345) → '12,345'

In the US and UK, the digits of numbers are grouped with commas every three digits. For example, the number 79033516 is written as 79,033,516 for readability. In this exercise, you’ll write a function that takes a number and returns a string of the number with comma formatting.

Exercise Description

Write a `commaFormat()`

function with a number parameter. The argument for this parameter can be
an integer or floating-point number. Your function returns a string of this
number with proper US/UK comma formatting. There is a comma after every third
digit in the whole number part. There are no commas at all in the fractional
part: The proper comma formatting of 1234.5678 is 1,234.5678 and not
1,234.567,8.

These Python `assert`

statements stop
the program if their condition is `False`

. Copy them
to the bottom of your solution program. Your solution is correct if the following
`assert`

statements’ conditions are all True:

assert commaFormat(1) == '1'

assert commaFormat(10) == '10'

assert commaFormat(100) == '100'

assert commaFormat(1000) == '1,000'

assert commaFormat(10000) == '10,000'

assert commaFormat(100000) == '100,000'

assert commaFormat(1000000) == '1,000,000'

assert commaFormat(1234567890) == '1,234,567,890'

assert commaFormat(1000.123456) == '1,000.123456'

Try to write a solution based on the information in this description. If you still have trouble solving this exercise, read the Solution Design and Special Cases and Gotchas sections for additional hints.

Prerequisite concepts: strings, `str()`

,
`in`

operator, `index()`

,
slices, string concatenation

Solution Design

Despite involving numbers, this exercise is actually about text manipulation. The characters of the string just happen to be numeric digits.

First, we convert the `number`

argument
to a string with the `str()`

function. This will work whether
the number is an integer or a floating-point number. Once we have the number as a string, we can check for the existence of a
period which indicates it was a floating-point number with a fractional part. The
expression `'.' in number`

evaluates to True if the string in number has a period character. Next,
we can use `number.index('.')`

to find the index of
this period character. (The `index()`

method raises a ValueError exception if `'.'`

doesn’t appear in the string, but the previous `'.'`

in number expression being `True`

guarantees that it
does.)

We need to remove this fractional part from `number`

while saving it in another variable to add back in later. This way we are only
adding commas to the whole number part of the `number`

argument, whether or not it was an integer or floating-point number.

Next, let’s start variables named `triplet`

and `commaNumber`

as blank strings. As we loop over
the digits of `number`

, the `triplet`

variable will store digits until it has three of them, at which point we add
them to `commaNumber`

(which contains the
comma-formatted version of number) with a comma. The first time we add triplet to `commaNumber`

, there
will be an extra comma at the end of a number. For example, the triplet '248' gets added to `commaNumber`

as `'248,'`

. We can remove the extra comma just before
returning the number.

We need to loop starting at the one’s place in the number and
moving left, so our `for`

loop should work in reverse:
`for i in range(len(number) - 1, -1, -1)`

. For
example, if `number`

is `4096`

,
then the first iteration of the loop can access `number[3]`

,
the second iteration can access `number[2]`

, and so
on. This way the first triplet ends up being `'096'`

instead of `'409'`

.

If the loop finishes and there are leftover digits in triplet, add them to `commaNumber`

with a comma. Finally, return `commaNumber`

except
with the comma at the end truncated: `commaNumber[:-1]`

evaluates to everything in `commaNumber`

except the
last character.

Finally, we need to add the fractional part back in the number if there was one originally.

Special Cases and Gotchas

Several bugs that can occur in our code. We should consider them ahead of writing our code so we can ensure they don’t sneak past us. These bugs could include:

·
A comma at the end of number, e.g., `386`

producing `'386,'`

·
A comma at the front of a number, e.g., `499000`

producing `',499,000'`

·
Commas appearing in the fraction part, e.g., `12.3333`

producing `'12.3,333'`

·
Grouping triplets in reverse order, e.g., `4096`

producing `'409,6'`

However you tackle this exercise, ensure that your code doesn’t make any of these mistakes.

Now try to write a solution based on the information in the previous sections. If you still have trouble solving this exercise, read the Solution Template section for additional hints.

Solution Template

Try to first write a solution from scratch. But if you have difficulty, you can use the following partial program as a starting place. Copy the following code from https://invpy.com/commaformat-template.py and paste it into your code editor. Replace the underscores with code to make a working program:

def commaFormat(number):

# Convert the number to a string:

number = str(____)

# Remember the fractional part and remove it from the number, if any:

if '.' in ____:

fractionalPart = number[number.index(____):]

number = number[:number.index('.')]

else:

fractionalPart = ''

# Create a variable to hold triplets of digits and the

# comma-formatted string as it is built:

triplet = ____

commaNumber = ____

# Loop over the digits starting on the right side and going left:

for i in range(len(number) - 1, ____, ____):

# Add the digits to the triplet variable:

triplet = ____[i] + ____

# When the triplet variable has three digits, add it with a

# comma to the comma-formatted string:

if ____(triplet) == ____:

commaNumber = triplet + ',' + ____

# Reset the triplet variable back to a blank string:

triplet = ____

# If the triplet has any digits left over, add it with a comma

# to the comma-formatted string:

if triplet != '':

commaNumber = ____ + ',' + ____

# Return the comma-formatted string:

return ____[:____] + fractionalPart

The complete solution for this exercise is given in Appendix A and https://invpy.com/commaformat.py. You can view each step of this program as it runs under a debugger at https://invpy.com/commaformat-debug/.

Prev - #32 Convert Strings To Integers | Table of Contents | Next - #34 Uppercase Letters