[Tutor] String Formatting

Isr Gish isrgish at fastem.com
Fri Sep 10 23:21:49 CEST 2004


Thanks Kent, I'll try it when I get a chence.

All the best,
Isr


-----Original Message-----
   >From: "Kent Johnson"<kent_johnson at skillsoft.com>
   >Sent: 9/10/04 12:08:16 PM
   >To: "tutor at python.org"<tutor at python.org>
   >Subject: Re: [Tutor] String Formatting
   >
   >I'm always up for an optimization challenge :-) I tried several methods. 
   >Other than the locale-based solution, they all work for non-negative 
   >integers only. Here is the fastest one I found. It takes about 1/10 the 
   >time of the locale version and wouldn't be too hard to modify to work for 
   >negative integers also.
   >
   >def commafy(val):
   >     ''' Straightforward approach using string slices '''
   >     s = str(val)
   >     start = len(s) % 3
   >
   >     chunks = []
   >     if start > 0:
   >         chunks.append(s[:start])
   >
   >     for i in range(start, len(s), 3):
   >         chunks.append(s[i:i+3])
   >
   >     return ','.join(chunks)
   >
   >Note that much of the time of the locale version is in accessing and 
   >switching locales. If you can set the locale once before doing the 
   >conversions, it is about 3x faster than the version that sets and restores 
   >the locale.
   >
   >Here are all the versions I tried and a timing harness to compare them. The 
   >output I get is this:
   >commafy1: 1.052021 secs
   >commafy2: 1.116770 secs
   >commafy3: 1.067124 secs
   >commafy4: 2.469994 secs
   >commafy5: 1.125030 secs
   >commafyLocale: 7.309395 secs
   >commafyLocale2: 3.077568 secs
   >
   >Kent
   >
   >###############################################
   ># commafy 1 to 3 are all variations on string slice and join
   >def commafy1(val):
   >     ''' Straightforward approach using string slices '''
   >     s = str(val)
   >     start = len(s) % 3
   >
   >     chunks = []
   >     if start > 0:
   >         chunks.append(s[:start])
   >
   >     for i in range(start, len(s), 3):
   >         chunks.append(s[i:i+3])
   >
   >     return ','.join(chunks)
   >
   >
   >def commafy2(val):
   >     ''' Use list.extend() instead of an append loop '''
   >     s = str(val)
   >     start = len(s) % 3
   >
   >     chunks = []
   >     if start > 0:
   >         chunks.append(s[:start])
   >
   >     chunks.extend([s[i:i+3] for i in range(start, len(s), 3)])
   >
   >     return ','.join(chunks)
   >
   >
   >def commafy3(val):
   >     ''' Use a list comprehension instead of a loop. The initial
   >         segment is a problem. '''
   >     s = str(val)
   >     start = len(s) % 3
   >
   >     chunks = [s[i:i+3] for i in range(start, len(s), 3)]
   >     if start > 0:
   >         chunks.insert(0, s[:start])
   >
   >     return ','.join(chunks)
   >
   >
   >def commafy4(val):
   >     ''' Iterate over the input and insert the commas directly '''
   >     s = list(str(val))
   >     s.reverse()
   >     i = iter(s)
   >     result = []
   >     while True:
   >         try:
   >             result.append(i.next())
   >             result.append(i.next())
   >             result.append(i.next())
   >             result.append(',')
   >         except StopIteration:
   >             if result[-1] == ',': result.pop()
   >             break
   >     result.reverse()
   >     return ''.join(result)
   >
   >
   >def commafy5(val):
   >     ''' Use divmod to make the chunks '''
   >     if val == 0: return '0'
   >
   >     chunks = []
   >     while val > 999:
   >         val, rem = divmod(val, 1000)
   >         chunks.append(str(rem).zfill(3))
   >     chunks.append(str(val))
   >     chunks.reverse()
   >     return ','.join(chunks)
   >
   >
   >import locale
   >def commafyLocale(val):
   >     ''' Official solution using locale module '''
   >     oldloc = locale.setlocale(locale.LC_ALL)
   >     locale.setlocale(locale.LC_ALL, 'en')
   >     result = locale.format('%d', val, True)
   >     locale.setlocale(locale.LC_ALL, oldloc)
   >     return result
   >
   >
   >locale.setlocale(locale.LC_ALL, 'en')   # This line speeds up the ABOVE 
   >version by 30% !
   >def commafyLocale2(val):
   >     ''' Use locale module but don't change locale '''
   >     result = locale.format('%d', val, True)
   >     return result
   >
   >
   ># timing test
   >import timeit
   >def test(f):
   >     return [f(10**i) for i in range(11)]
   >
   >correctAnswer = [
   >'1',
   >'10',
   >'100',
   >'1,000',
   >'10,000',
   >'100,000',
   >'1,000,000',
   >'10,000,000',
   >'100,000,000',
   >'1,000,000,000',
   >'10,000,000,000',
   >]
   >
   >def timeOne(fn):
   >     # First run the function and check that it gets the correct results
   >     actualAnswer = test(fn)
   >     if actualAnswer != correctAnswer:
   >         print fn.__name__, 'does not give the correct answer'
   >         print actualAnswer
   >         return
   >
   >     # Now time it
   >     setup = "from __main__ import test, " + fn.__name__
   >     stmt = 'test(%s)' % fn.__name__
   >
   >     t = timeit.Timer(stmt, setup)
   >     secs = t.timeit(10000)
   >     print '%s: %f secs' % (fn.__name__, secs)
   >
   >
   >fnsToTest = [
   >     commafy1,
   >     commafy2,
   >     commafy3,
   >     commafy4,
   >     commafy5,
   >     commafyLocale,
   >     commafyLocale2,
   >]
   >
   >for fn in fnsToTest:
   >     timeOne(fn)
   >
   >
   >At 10:34 AM 9/10/2004 -0400, Isr Gish wrote:
   >>Thanks orbitz,
   >>
   >>But...
   >>
   >>    >oldloc = locale.setlocale(locale.LC_ALL)
   >>    >locale.setlocale(locale.LC_ALL, 'en_US')
   >>    >locale.format('%d', some_num, True)
   >>    >locale.setlocale(locale.LC_ALL, oldloc)
   >>    >
   >>
   >>I would rather not use this way, iit takes about 25 times longer then a 
   >>regular % format. And I'm using it for about 1,000,000 times.
   >>
   >>Isr
   >>
   >>-----Original Message-----
   >>    >From: "orbitz"<orbitz at ezabel.com>
   >>    >Sent: 9/9/04 10:55:22 PM
   >>    >To: "Isr Gish"<isrgish at fastem.com>, "tutor at python.org"<tutor at python.org>
   >>    >Subject: Re: [Tutor] String Formatting
   >>    >
   >>    >Easiest way would probably be using locale.format in some code I do:
   >>    >
   >>    >oldloc = locale.setlocale(locale.LC_ALL)
   >>    >locale.setlocale(locale.LC_ALL, 'en_US')
   >>    >locale.format('%d', some_num, True)
   >>    >locale.setlocale(locale.LC_ALL, oldloc)
   >>    >
   >>    >
   >>    >Isr Gish wrote:
   >>    >
   >>    >>Hi,
   >>    >>
   >>    >>How can I format a integer in a format string with a comma for example
   >>    >>print 'Your Account has %f' %amount
   >>    >>That should print:
   >>    >>Your Account has 1,000.00
   >>    >>
   >>    >>Thanks
   >>    >>Isr
   >>    >>
   >>    >>_______________________________________________
   >>    >>Tutor maillist  -  Tutor at python.org
   >>    >>http://mail.python.org/mailman/listinfo/tutor
   >>    >>
   >>    >>
   >>    >>
   >>    >
   >>
   >>_______________________________________________
   >>Tutor maillist  -  Tutor at python.org
   >>http://mail.python.org/mailman/listinfo/tutor
   >
   >_______________________________________________
   >Tutor maillist  -  Tutor at python.org
   >http://mail.python.org/mailman/listinfo/tutor



More information about the Tutor mailing list