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

Exercise #33: Comma-Formatted Numbers

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