Ari
Ari

Reputation: 6199

Format a large integer with commas without using .format()

I'm trying to format any number by inserting ',' every 3 numbers from the end by not using format()

123456789 becomes 123,456,789

1000000 becomes 1,000,000

What I have so far only seems to go from the start, I've tried different ideas to get it to reverse but they seem to not work as I hoped.

def format_number(number):
    s = [x for x in str(number)]

    for a in s[::3]:
        if s.index(a) is not 0:
             s.insert(s.index(a), ',')
    return ''.join(s)

print(format_number(1123456789))

>> 112,345,678,9

But obviously what I want is 1,123,456,789

I tried reversing the range [:-1:3] but I get 112,345,6789

Clarification: I don't want to use format to structure the number, I'd prefer to understand how to do it myself just for self-study's sake.

Upvotes: 0

Views: 2806

Answers (3)

Stuart
Stuart

Reputation: 9868

One way to do it without built-in functions at all...

def format_number(number):
    i = 0
    r = ""
    while True:
        r = "0123456789"[number % 10] + r
        number //= 10
        if number == 0:
            return r
        i += 1
        if i % 3 == 0:
            r = "," + r

Here's a version that's almost free of built-in functions or methods (it does still have to use str)

def format_number(number):
    i = 0
    r = ""
    for character in str(number)[::-1]:
        if i > 0 and i % 3 == 0:
            r = "," + r
        r = character + r
        i += 1

    return r

Another way to do it without format but with other built-ins is to reverse the number, split it into chunks of 3, join them with a comma, and reverse it again.

def format_number(number):
    backward = str(number)[::-1]
    r = ",".join(backward[i:i+3] for i in range(0, len(backward), 3))
    return r[::-1]

Upvotes: 2

Azat Ibrakov
Azat Ibrakov

Reputation: 11009

Your current approach has following drawbacks

  • checking for equality/inequality in most cases (especially for int) should be made using ==/!= operators, not is/is not ones,
  • using list.index returns first occurence from the left end (so s.index('1') will be always 0 in your example), we can iterate over range if indices instead (using range built-in).

we can have something like

def format_number(number):
    s = [x for x in str(number)]
    for index in range(len(s) - 3, 0, -3):
        s.insert(index, ',')
    return ''.join(s)

Test

>>> format_number(1123456789)
'1,123,456,789'
>>> format_number(6789)
'6,789'
>>> format_number(135)
'135'

If range, list.insert and str.join are not allowed

We can replace

  • range with while loop,
  • list.insert using slicing and concatenation,
  • str.join with concatenation,

like

def format_number(number):
    s = [x for x in str(number)]
    index = len(s) - 3
    while index > 0:
        s = s[:index] + [','] + s[index:]
        index -= 3
    result = ''
    for character in s:
        result += character
    return result

Using str.format

Finally, following docs

The ',' option signals the use of a comma for a thousands separator. For a locale aware separator, use the 'n' integer presentation type instead.

your function can be simplified to

def format_number(number):
    return '{:,}'.format(number)

and it will even work for floats.

Upvotes: 1

Aiden Blishen Cuneo
Aiden Blishen Cuneo

Reputation: 369

Here is a solution for you, without using built-in functions:

def format_number(number):
    s = list(str(number))[::-1]
    o = ''
    for a in range(len(s)):
        if a and a % 3 == 0:
            o += ','
        o += s[a]
    return o[::-1]


print(format_number(1123456789))

And here is the same solution using built-in functions:

def format_number(number):
    return '{:,}'.format(number)


print(format_number(1123456789))

I hope this helps. :D

Upvotes: 2

Related Questions