From: John Nagle on
There's got to be a better way to do this:


def editmoney(n) :
return((",".join(reduce(lambda lst, item : (lst + [item]) if
item else lst,
re.split(r'(\d\d\d)',str(n)[::-1]),[])))[::-1])


>>> editmoney(0)
'0'
>>> editmoney(13535)
'13,535'
>>> editmoney(-14535)
'-14,535'
>>> editmoney(123456)
'123,456'
>>> editmoney(1234567890)
'1,234,567,890'
>>> editmoney(-1234)
'-1,234'

The basic idea here is that we want to split the string of digits
into groups of 3 digits, aligned at the right. Because regular
expressions are right to left, we have to reverse the string to
do that, then reverse again at the end. s[::-1} reverses an
interable.

"split" with a capturing group introduces empty strings into the
list. Hence the "reduce" and lambda to get rid of them.

Any better ideas?

(Yes, I know there's a built-in feature for this scheduled for
Python 2.7.)

John Nagle


From: Paul Rubin on
John Nagle <nagle(a)animats.com> writes:
> def editmoney(n) :
> return((",".join(reduce(lambda lst, item : (lst + [item]) if
> item else lst,
> re.split(r'(\d\d\d)',str(n)[::-1]),[])))[::-1])

Too obscure. I usually use something like this:

def editmoney(n):
if n < 0: return '-' + editmoney(-n)
if n >= 1000:
return editmoney(n // 1000) + ',%03d'% (n % 1000)
return '%d'% n
From: Steven D'Aprano on
On Wed, 04 Aug 2010 21:33:31 -0700, John Nagle wrote:

> There's got to be a better way to do this:
>
>
> def editmoney(n) :
> return((",".join(reduce(lambda lst, item : (lst + [item]) if
> item else lst,
> re.split(r'(\d\d\d)',str(n)[::-1]),[])))[::-1])

What does the name "editmoney" mean?

Why the obfuscated one-liner? It's not like you're using it in-line,
you're putting it in a function, so who cares if it's one line or twenty?

def group_digits(n, size=3, sep=','):
"""Group int n in groups of size digits separated by sep."""
s = str(n)
m = len(s) % size
head = s[0:m]
tail = s[m:]
groups = [tail[i*size:(i+1)*size] for i in range(len(tail)//size)]
tail = sep.join(groups)
if head and tail:
return head + sep + tail
elif tail:
return tail
else:
return head


>>> group_digits(0)
'0'
>>> group_digits(1234567890)
'1,234,567,890'
>>> group_digits(1234567890, 4, ';')
'12;3456;7890'


Additional error checking, a better docstring, and extending it to
support negative numbers is left as an exercise.



--
Steven
From: Peter Otten on
John Nagle wrote:

> There's got to be a better way to do this:
>
>
> def editmoney(n) :
> return((",".join(reduce(lambda lst, item : (lst + [item]) if
> item else lst,
> re.split(r'(\d\d\d)',str(n)[::-1]),[])))[::-1])
>
>
> >>> editmoney(0)
> '0'
> >>> editmoney(13535)
> '13,535'
> >>> editmoney(-14535)
> '-14,535'
> >>> editmoney(123456)
> '123,456'
> >>> editmoney(1234567890)
> '1,234,567,890'
> >>> editmoney(-1234)
> '-1,234'
>
> The basic idea here is that we want to split the string of digits
> into groups of 3 digits, aligned at the right. Because regular
> expressions are right to left, we have to reverse the string to
> do that, then reverse again at the end. s[::-1} reverses an
> interable.
>
> "split" with a capturing group introduces empty strings into the
> list. Hence the "reduce" and lambda to get rid of them.
>
> Any better ideas?
>
> (Yes, I know there's a built-in feature for this scheduled for
> Python 2.7.)


>>> locale.setlocale(locale.LC_ALL, ("en_US", "UTF-8"))
'en_US.UTF8'
>>> print locale.currency(13535, grouping=True)
$13,535.00
>>> print locale.format("%d", 13535, grouping=True)
13,535

>>> locale.setlocale(locale.LC_ALL, "")
'de_DE.UTF-8'
>>> print locale.currency(13535, grouping=True)
13.535,00 €
>>> print locale.format("%d", 13535, grouping=True)
13.535

Peter

From: geremy condra on
On Wed, Aug 4, 2010 at 11:30 PM, Peter Otten <__peter__(a)web.de> wrote:
> John Nagle wrote:
>
>> There's got to be a better way to do this:
>>
>>
>> def editmoney(n) :
>>      return((",".join(reduce(lambda lst, item : (lst + [item]) if
>>          item else lst,
>>          re.split(r'(\d\d\d)',str(n)[::-1]),[])))[::-1])
>>
>>
>>  >>> editmoney(0)
>> '0'
>>  >>> editmoney(13535)
>> '13,535'
>>  >>> editmoney(-14535)
>> '-14,535'
>>  >>> editmoney(123456)
>> '123,456'
>>  >>> editmoney(1234567890)
>> '1,234,567,890'
>>  >>> editmoney(-1234)
>> '-1,234'
>>
>> The basic idea here is that we want to split the string of digits
>> into groups of 3 digits, aligned at the right.  Because regular
>> expressions are right to left, we have to reverse the string to
>> do that, then reverse again at the end.  s[::-1} reverses an
>> interable.
>>
>> "split" with a capturing group introduces empty strings into the
>> list.  Hence the "reduce" and lambda to get rid of them.
>>
>> Any better ideas?
>>
>> (Yes, I know there's a built-in feature for this scheduled for
>> Python 2.7.)
>
>
>>>> locale.setlocale(locale.LC_ALL, ("en_US", "UTF-8"))
> 'en_US.UTF8'
>>>> print locale.currency(13535, grouping=True)
> $13,535.00
>>>> print locale.format("%d", 13535, grouping=True)
> 13,535
>
>>>> locale.setlocale(locale.LC_ALL, "")
> 'de_DE.UTF-8'
>>>> print locale.currency(13535, grouping=True)
> 13.535,00 €
>>>> print locale.format("%d", 13535, grouping=True)
> 13.535
>
> Peter

I had literally no idea this existed. Thanks.

Geremy Condra