Python Programming
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me

The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.

Go Back   Dev Shed ForumsProgramming LanguagesPython Programming

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old February 12th, 2004, 01:18 AM
theperfectsoup theperfectsoup is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2003
Posts: 35 theperfectsoup User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 10
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

Reply With Quote
  #2  
Old February 12th, 2004, 09:59 AM
netytan's Avatar
netytan netytan is offline
Hello World :)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Mar 2003
Location: Hull, UK
Posts: 2,537 netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level) 
Time spent in forums: 1 Week 2 Days 18 h 17 m 47 sec
Reputation Power: 68
Send a message via ICQ to netytan Send a message via AIM to netytan Send a message via MSN to netytan Send a message via Yahoo to netytan
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.
__________________
programming language development: www.netytan.com Hula


Last edited by netytan : February 12th, 2004 at 04:26 PM.

Reply With Quote
  #3  
Old February 12th, 2004, 11:14 AM
netytan's Avatar
netytan netytan is offline
Hello World :)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Mar 2003
Location: Hull, UK
Posts: 2,537 netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level) 
Time spent in forums: 1 Week 2 Days 18 h 17 m 47 sec
Reputation Power: 68
Send a message via ICQ to netytan Send a message via AIM to netytan Send a message via MSN to netytan Send a message via Yahoo to netytan
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 04:25 PM.

Reply With Quote
  #4  
Old February 12th, 2004, 03:42 PM
Strike Strike is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Dec 2001
Location: Houston, TX
Posts: 383 Strike User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 41 m 27 sec
Reputation Power: 12
Send a message via ICQ to Strike Send a message via AIM to Strike Send a message via Yahoo to Strike
netytan: FYI, it's list comprehensions, not compressions

Reply With Quote
  #5  
Old February 12th, 2004, 04:24 PM
netytan's Avatar
netytan netytan is offline
Hello World :)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Mar 2003
Location: Hull, UK
Posts: 2,537 netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level) 
Time spent in forums: 1 Week 2 Days 18 h 17 m 47 sec
Reputation Power: 68
Send a message via ICQ to netytan Send a message via AIM to netytan Send a message via MSN to netytan Send a message via Yahoo to netytan
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.

Reply With Quote
  #6  
Old February 12th, 2004, 04:49 PM
percivall percivall is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jul 2003
Posts: 133 percivall User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 10
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 05:07 PM.

Reply With Quote
  #7  
Old February 12th, 2004, 07:56 PM
Strike Strike is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Dec 2001
Location: Houston, TX
Posts: 383 Strike User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 41 m 27 sec
Reputation Power: 12
Send a message via ICQ to Strike Send a message via AIM to Strike Send a message via Yahoo to Strike
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.

Reply With Quote
  #8  
Old February 13th, 2004, 02:58 AM
Grim Archon's Avatar
Grim Archon Grim Archon is offline
Mini me.
Dev Shed Novice (500 - 999 posts)
 
Join Date: Nov 2003
Location: Cambridge, UK
Posts: 783 Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)  Folding Points: 1488 Folding Title: Novice Folder
Time spent in forums: 3 Days 2 h 15 m 57 sec
Reputation Power: 12
Send a message via MSN to Grim Archon
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

Reply With Quote
  #9  
Old February 13th, 2004, 05:23 PM
netytan's Avatar
netytan netytan is offline
Hello World :)
Dev Shed Frequenter (2500 - 2999 posts)
 
Join Date: Mar 2003
Location: Hull, UK
Posts: 2,537 netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level)netytan User rank is Second Lieutenant (5000 - 10000 Reputation Level) 
Time spent in forums: 1 Week 2 Days 18 h 17 m 47 sec
Reputation Power: 68
Send a message via ICQ to netytan Send a message via AIM to netytan Send a message via MSN to netytan Send a message via Yahoo to netytan
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.

Reply With Quote
  #10  
Old February 13th, 2004, 06:18 PM
Grim Archon's Avatar
Grim Archon Grim Archon is offline
Mini me.
Dev Shed Novice (500 - 999 posts)
 
Join Date: Nov 2003
Location: Cambridge, UK
Posts: 783 Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)  Folding Points: 1488 Folding Title: Novice Folder
Time spent in forums: 3 Days 2 h 15 m 57 sec
Reputation Power: 12
Send a message via MSN to Grim Archon
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

Reply With Quote
  #11  
Old February 19th, 2004, 11:32 AM
DevCoach DevCoach is offline
Contributing User
Dev Shed Intermediate (1500 - 1999 posts)
 
Join Date: Feb 2004
Location: London, England
Posts: 1,585 DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level) 
Time spent in forums: 2 Weeks 4 Days 2 h 58 m 23 sec
Reputation Power: 1372
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 11:37 AM. Reason: fixed typo in the code

Reply With Quote
  #12  
Old February 19th, 2004, 04:27 PM
Grim Archon's Avatar
Grim Archon Grim Archon is offline
Mini me.
Dev Shed Novice (500 - 999 posts)
 
Join Date: Nov 2003
Location: Cambridge, UK
Posts: 783 Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)  Folding Points: 1488 Folding Title: Novice Folder
Time spent in forums: 3 Days 2 h 15 m 57 sec
Reputation Power: 12
Send a message via MSN to Grim Archon
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
__________________
*** Experimental Python Markup CGI V2 ***

Last edited by Grim Archon : February 19th, 2004 at 04:35 PM. Reason: Added facts.

Reply With Quote
  #13  
Old February 19th, 2004, 05:29 PM
DevCoach DevCoach is offline
Contributing User
Dev Shed Intermediate (1500 - 1999 posts)
 
Join Date: Feb 2004
Location: London, England
Posts: 1,585 DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level)DevCoach User rank is General 6th Grade (Above 100000 Reputation Level) 
Time spent in forums: 2 Weeks 4 Days 2 h 58 m 23 sec
Reputation Power: 1372
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

Reply With Quote
  #14  
Old February 20th, 2004, 04:34 AM
Grim Archon's Avatar
Grim Archon Grim Archon is offline
Mini me.
Dev Shed Novice (500 - 999 posts)
 
Join Date: Nov 2003
Location: Cambridge, UK
Posts: 783 Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)Grim Archon User rank is Corporal (100 - 500 Reputation Level)  Folding Points: 1488 Folding Title: Novice Folder
Time spent in forums: 3 Days 2 h 15 m 57 sec
Reputation Power: 12
Send a message via MSN to Grim Archon
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

Reply With Quote
  #15  
Old February 20th, 2004, 07:33 AM
Strike Strike is offline
Contributing User
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Dec 2001
Location: Houston, TX
Posts: 383 Strike User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: 1 h 41 m 27 sec
Reputation Power: 12
Send a message via ICQ to Strike Send a message via AIM to Strike Send a message via Yahoo to Strike
Quote:
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.

Reply With Quote
Reply

Viewing: Dev Shed ForumsProgramming LanguagesPython Programming > Injecting commas to long numbers?

Developer Shed Advertisers and Affiliates



Thread Tools  Search this Thread 
Search this Thread:

Advanced Search
Display Modes  Rate This Thread 
Rate This Thread:


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
View Your Warnings | New Posts | Latest News | Latest Threads | Shoutbox
Forum Jump

Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
  
 


Powered by: vBulletin Version 3.0.5
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.

© 2003-2013 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap