Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Posts
    35
    Rep Power
    12

    Injecting commas to long numbers?


    Hi all,

    Anyone know of a built-in or easy way to turn a number like 3961037749 into the string "3,961,037,749"?

    Thanks,
    tps
  2. #2
  3. Hello World :)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2003
    Location
    Hull, UK
    Posts
    2,537
    Rep Power
    69
    There might be a betetr way to do this but i'm not aware of it if there is.. sooo, i've writen a few different versions of the inject functions.

    Code:
    def inject(number):
    	string = str(number)
    	cursor = 0
    	output = []
    
    	for number in string[::-1]:
    		if not cursor % 3:
    			number = number + ','
    		cursor = cursor + 1
    		output.append(number)
    		
    	output.reverse()
    
    	return ''.join(output)[:-1]
    Code:
    def inject(number):
    	string = str(number)
    	output = []
    	
    	for index, value in enumerate(string):
    		if not index % 3:
    			value = string[index - len(string)] + ','
    		output.append(value)
    	return ''.join(output)[:-1]
    I'm also gonna see if this can be done with list comprehensions. We'll see

    Mark.
    Last edited by netytan; February 12th, 2004 at 05:26 PM.
    programming language development: www.netytan.com Hula

  4. #3
  5. Hello World :)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2003
    Location
    Hull, UK
    Posts
    2,537
    Rep Power
    69
    Ok admitadly this is actualy two functions but unfortunatly needed...

    Code:
    def insert(i, v):
    	if not i % 3: v = v + ','; return v
    
    def inject(n):
    	return ''.join([insert(i, v) for i, v in enumerate(str(n))])[:-1]
    Obviously using list comprehensions . Which has its limitations. Still works though , although personally i'd use one of the functions above.

    Mark.
    Last edited by netytan; February 12th, 2004 at 05:25 PM.
    programming language development: www.netytan.com Hula

  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2001
    Location
    Houston, TX
    Posts
    383
    Rep Power
    14
    netytan: FYI, it's list comprehensions, not compressions
  8. #5
  9. Hello World :)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2003
    Location
    Hull, UK
    Posts
    2,537
    Rep Power
    69
    Hahhaha i so didn't spot that need to think more . Ah it could be worse though, this guy i used to work for couldnt stop himself typing sausage instead of some word... every time he tried to type this word he'd type sausage lol

    Mark.
    programming language development: www.netytan.com Hula

  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Posts
    133
    Rep Power
    12
    Here's a nice and uncomplicated implementation that might be fun to parse:
    Code:
    def commatize(num):
        if type(num) is not str:
            num = str(num)
        return ",".join([part for part in\
                         [num[x*-3:len(num)+3+(x*-3)]
                          for x in range(1, len(num) / 3 + 2)][::-1]
                         if len(part) != 0])
    This is the true one-liner, considering that you could easily remove the "if type..." part of the code. On the other hand: I too would rather use the more verbose code.
    Last edited by percivall; February 12th, 2004 at 06:07 PM.
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2001
    Location
    Houston, TX
    Posts
    383
    Rep Power
    14
    Another version, just for fun:
    Code:
    def commatize(num):
        L = list(str(num))
        for add, pos in enumerate(range(3, len(L), 3)):
            L.insert(-(add+pos), ',')
        return ''.join(L)
    it's sort of the one-function version of netytan's shortest.
  14. #8
  15. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    14
    Just adding to the mix
    The Good :
    Code:
    def comma5(num):
        d = `num`[::-1]
        r = ''
        for c in range(0,len(d),3):
            r = r+d[0:3]+','
            d = d[3:]
        if r[-1] == ',':
            r = r[:-1]
        return r[::-1]
    The Bad and the Ugly(ist) code I've ever written
    Code:
    def comma3(num):
        d= ''.join(map(lambda x, y : x+[',',''][(y+1)%3 and 1],list(`num`)[::-1],range(len(list(`a`)))))
        return d[:len(d)-(d[-1]==',')][::-1]
    comma5 is fast, comma3 is SO slow.
    Grim
  16. #9
  17. Hello World :)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Mar 2003
    Location
    Hull, UK
    Posts
    2,537
    Rep Power
    69
    Ok i finally got it figured it out, with a little inspiration from you're examples.

    No i don't clame its the most efficent function because i can see places that could be improved on i.e. the two str() calls would normally be singular, but since the aim of this example was to write a totaly self contained one liner it had to be so.

    Code:
    def inject(number): return ','.join([str(number)[::-1][index:index + 3][::-1] for index in range(0, len(str(number)), 3)][::-1])
    If you can see ways to shorten this further i'd love to hear them.

    Grim: way, you were right, you can do this with map and lambda *shakes you're hand as promised*

    Mark.
    programming language development: www.netytan.com Hula

  18. #10
  19. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    14
    Netyan,full marks for
    But, my comma5 is still twice as fast as the worst posted (my comma3 func ) and 40% faster than the next best
    Grim
  20. #11
  21. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Feb 2004
    Location
    London, England
    Posts
    1,585
    Rep Power
    1373

    A recursive alternative


    All the solutions given so far work by treating the number as a string or list of characters, and chopping it up/inserting characters.

    Here is an alternative that works by recursively dividing the number by 1000:

    Code:
    >>> def comma(x): return x < 1000 and str(x) or ('%s,%03d' % (comma(x//1000), (x%1000)))
    ...
    >>> comma(30498523409562345923459085340L)
    '30,498,523,409,562,345,923,459,085,340'
    I have not benchmarked it against the other versions - that is left as an exercise for the reader.

    The function also only works with positive integers. It can be made to work with negative numbers, but would not be such a neat one-liner.

    Dave - The Developers' Coach
    Last edited by DevCoach; February 19th, 2004 at 12:37 PM. Reason: fixed typo in the code
  22. #12
  23. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    14
    Dave, that must be the last word in compactness and speed. A full 6% faster than my best effort
    Another one to hurt my head
    Grim
    Last edited by Grim Archon; February 19th, 2004 at 05:35 PM. Reason: Added facts.
  24. #13
  25. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Feb 2004
    Location
    London, England
    Posts
    1,585
    Rep Power
    1373

    improved recursive version


    I have played around with this some more, and done some benchmarking. I found that two of the given solutions did not run, and two others gave the wrong answers for long integers (because the conversion to string added an 'L' on the end, which screwed up their indexing).

    Of the ones that ran, my version was fastest for integers and grim's comma5 function was slightly faster for longs.

    However all the functions so far failed for negative numbers - mine just returned the number unchanged, and all the others (that worked) when given a number like:

    -450324598

    returned:

    -,450,324,598

    here is a new version of my recursive function that correctly handles all cases, and has been re-written to be easier to read (this is Python after all, not Perl)

    Code:
    def comma(x):
       if x < 0: return '-' + comma(-x)
       if x < 1000: return str(x)
       return '%s,%03d' % (comma(x//1000), (x%1000))
    Incidentally, the '//' operator is the 'floor division' operator introduced in 2.2 - for earlier versions of Python use '/'. At the moment they both give the same result, but in the future (I think in 2.4) the '/' operator on integers will convert the answer to a float when necessary.

    Have a nice day

    Dave - The Developers' Coach
  26. #14
  27. Mini me.
    Devshed Novice (500 - 999 posts)

    Join Date
    Nov 2003
    Location
    Cambridge, UK
    Posts
    783
    Rep Power
    14
    Here's my version fixed for the issues Dave mentioned and with a minor speed tweak
    Code:
    def comma5(num):
        if num < 0: return '-' + comma5(-num)
        d = `num`[::-1]
        r = ''
        for c in range(type(num)==type(1L),len(d),3):
            r += d[c:c+3]+','
        if r[-1] == ',':
            r = r[:-1]
        return r[::-1]
    results for calling each function 100,000 times show that for everyday numbers, Dave's method is fastest:
    Code:
                                      Number  comma5  comma   Diff%
                                           1 | 1.410 | 0.277 |-80.362
                                       4,096 | 1.630 | 0.858 |-47.390
                                  16,777,216 | 1.803 | 1.351 |-25.052
                               4,294,967,296 | 2.019 | 2.161 |7.065
                              68,719,476,736 | 2.026 | 2.177 |7.435
                           1,099,511,627,776 | 2.155 | 2.727 |26.539
                   1,152,921,504,606,846,976 | 2.476 | 3.840 |55.069
               4,722,366,482,869,645,213,696 | 2.649 | 4.409 |66.481
              75,557,863,725,914,323,419,136 | 2.673 | 4.427 |65.626
    The switch from integer to long has an impact in Dave's method at which point the string method becomes best. With a very small performance hit to each method the following hybrid makes a good compromise for best overall performance with the current math libraries:
    Code:
    def comma_hybrid(num):
        if num < 0: return '-' + comma_hybrid(-num)
        if num < 1000: return str(num)
        if num > 2147483647:
            d = `num`[::-1]
            r = ''
            for c in range(type(num)==type(1L),len(d),3):
                r += d[c:c+3]+','
            if r[-1] == ',':
                r = r[:-1]
            return r[::-1]
        return '%s,%03d' % (comma_hybrid(num//1000), (num%1000))
    Grim
  28. #15
  29. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2001
    Location
    Houston, TX
    Posts
    383
    Rep Power
    14
    Originally Posted by Grim Archon
    Code:
        if num > 2147483647:
    I'm guessing you've never seen sys.maxint
    Debian - because life's too short for worrying.
    Best. (Python.) IRC bot. ever.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo