The Shed is going Social! Join us on FaceBook and Twitter and chime in on the conversation.
|
 |
|
Dev Shed Forums
> Programming Languages
> Python Programming
|
Injecting commas to long numbers?
Discuss Injecting commas to long numbers? in the Python Programming forum on Dev Shed. Injecting commas to long numbers? Python Programming forum discussing coding techniques, tips and tricks, and Zope related information. Python was designed from the ground up to be a completely object-oriented programming language.
|
|
 |
|
|
|
|
|

Dev Shed Forums Sponsor:
|
|
|

February 12th, 2004, 01:18 AM
|
|
Contributing User
|
|
Join Date: Jul 2003
Posts: 35
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
|

February 12th, 2004, 09:59 AM
|
 |
Hello World :)
|
|
Join Date: Mar 2003
Location: Hull, UK
|
|
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.
|

February 12th, 2004, 11:14 AM
|
 |
Hello World :)
|
|
Join Date: Mar 2003
Location: Hull, UK
|
|
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.
|

February 12th, 2004, 03:42 PM
|
|
Contributing User
|
|
Join Date: Dec 2001
Location: Houston, TX
Posts: 383
Time spent in forums: 1 h 41 m 27 sec
Reputation Power: 12
|
|
netytan: FYI, it's list comprehensions, not compressions 
|

February 12th, 2004, 04:24 PM
|
 |
Hello World :)
|
|
Join Date: Mar 2003
Location: Hull, UK
|
|
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.
|

February 12th, 2004, 04:49 PM
|
|
Contributing User
|
|
Join Date: Jul 2003
Posts: 133
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.
|

February 12th, 2004, 07:56 PM
|
|
Contributing User
|
|
Join Date: Dec 2001
Location: Houston, TX
Posts: 383
Time spent in forums: 1 h 41 m 27 sec
Reputation Power: 12
|
|
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.
|

February 13th, 2004, 02:58 AM
|
 |
Mini me.
|
|
Join Date: Nov 2003
Location: Cambridge, UK
|
|
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
|

February 13th, 2004, 05:23 PM
|
 |
Hello World :)
|
|
Join Date: Mar 2003
Location: Hull, UK
|
|
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.
|

February 13th, 2004, 06:18 PM
|
 |
Mini me.
|
|
Join Date: Nov 2003
Location: Cambridge, UK
|
|
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
|

February 19th, 2004, 11:32 AM
|
|
Contributing User
|
|
Join Date: Feb 2004
Location: London, England
|
|
|
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
|

February 19th, 2004, 04:27 PM
|
 |
Mini me.
|
|
Join Date: Nov 2003
Location: Cambridge, UK
|
|
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 04:35 PM.
Reason: Added facts.
|

February 19th, 2004, 05:29 PM
|
|
Contributing User
|
|
Join Date: Feb 2004
Location: London, England
|
|
|
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
|

February 20th, 2004, 04:34 AM
|
 |
Mini me.
|
|
Join Date: Nov 2003
Location: Cambridge, UK
|
|
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 
|

February 20th, 2004, 07:33 AM
|
|
Contributing User
|
|
Join Date: Dec 2001
Location: Houston, TX
Posts: 383
Time spent in forums: 1 h 41 m 27 sec
Reputation Power: 12
|
|
Quote: | Originally Posted by Grim Archon
Code:
if num > 2147483647:
|
I'm guessing you've never seen sys.maxint
|
Developer Shed Advertisers and Affiliates
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Rate This Thread |
Linear Mode
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
|