0

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.

Community
  • 1
  • 1
Ari
  • 5,301
  • 8
  • 46
  • 120
  • 1
    Can I ask why you don't want to use built-in functions? I'm sure a quick function could easily solve this for you. – Aiden Blishen Cuneo Jun 23 '19 at 01:26
  • You can use `[::-3]` instead. That will reverse the range. – GeeTransit Jun 23 '19 at 01:28
  • 3
    Aren't you using `print`, `index`, `insert` and `join`? Aren't they built-in? – Scott Hunter Jun 23 '19 at 01:32
  • Possible duplicate of [How to print number with commas as thousands separators?](https://stackoverflow.com/questions/1823058/how-to-print-number-with-commas-as-thousands-separators) – Azat Ibrakov Jun 23 '19 at 01:38
  • 1
    @AzatIbrakov: it's related, but not a dupe given the "without using builtin functions" requirement (even though that's not well-defined) – smci Jun 23 '19 at 01:43

3 Answers3

2

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

  • 2
    Technically `range`, `len`, `list` and `str` are all built-in functions... but then the OP's attempt also uses some of these. – Stuart Jun 23 '19 at 01:40
  • 1
    My question wasn't specific but you got what I was trying to say, I didn't want to use `.format()` but I wanted to try and do it manually, but couldn't. Thanks for being understanding! – Ari Jun 23 '19 at 01:53
2

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]
Stuart
  • 9,597
  • 1
  • 21
  • 30
1

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.

Azat Ibrakov
  • 9,998
  • 9
  • 38
  • 50