[Tutor] literal number (was: dictionaries)

Christian Ebert blacktrash@gmx.net
Wed, 27 Feb 2002 02:17:47 +0100

Danny Yoo on Thursday, February 21, 2002 21:34:36 :

> Yes, the sort() method of lists does it in-place, so the code above
> wouldn't work.  However, we can fix that.  Here's a function that'll
> return a new sorted list:
> ###
> def fsort(L, f=cmp):
>     """A "functional" sort that returns a copy of L, with all its contents
>        sorted out."""
>     L2 = L[:]
is this just a stylistic convention or does it make a
"functional" difference to L2 = L ?

>     L2.sort(f)
>     return L2
> ###

Hm, you got me addicted to those little functions. So I did
the same with reverse() and used it in one of my first
scripts - one could do all this less verbosely by
considering the number as a number and not a list of chars,
using modulo and so forth; but I'm no math guy, so this is
my approach:

def litNum(numstr):
    """Returns a literal representation of a positive number."""
    def fReverse(mylist):
        """Returns mylist in reversed order."""
        return mylist
    if numstr == '0': return 'NAUGHTy professor!'

    ones = ('', 'one', 'two', 'three', 'four',
        'five', 'six', 'seven', 'eight', 'nine')
    tens = ('', None, 'twenty', 'thirty', 'forty',
        'fifty', 'sixty', 'seventy', 'eighty', 'ninety')
    teenies = ('ten', 'eleven', 'twelve', 'thirteen', 'fourteen',
        'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen')
    powers = ('thousand', 'million', 'billion', 'trillion',
        'quadrillion', 'quintillion', 'sextillion')

    # list digits in reverse order:
    try: digits = fReverse(map(lambda x: int(x), numstr))
    except ValueError: return 'A positive integer please.'
    d = len(digits)       # count of digits
    digind = range(d)     # list indices of digits

    # initialize backward listing of literal representation of digits:
    strlist = [None for i in digind]

    for i in range(1, d, 3):
        strlist[i] = ''
        if max(digits[i-1:i+1]) and d > i+1:
            strlist[i] = 'and '
        if digits[i] == 1:
            strlist[i-1] = teenies[digits[i-1]]
            strlist[i] = '%s%s' % (strlist[i], tens[digits[i]])
            if digits[i] and digits[i-1]:
                strlist[i] = '%s-' % strlist[i]

    for i in digind:
        if strlist[i] == None:
            strlist[i] = ones[digits[i]]

        for i in range(3, d, 3):
            if max(digits[i:i+3]):
                strlist[i] = '%s %s ' % (strlist[i], powers[(i-1)/3])
    except IndexError:
        return 'Number goes beyond sextillions, I don\'t have a name for it.'

    for i in range(2, d, 3):
        if digits[i]:
            strlist[i] = '%s hundred' % strlist[i]
            if max(digits[i-2:i]):
                strlist[i] = '%s ' % strlist[i]

    # concatenate list of strings in right order:
    return ''.join(fReverse(strlist))

print litNum(raw_input('Enter a positive number to get its English literal: '))

I also made a German version, but hesitate to attack a
French one; e. g. 98 == "quatre-vingt dix-huit" ;-b

Hyperion in Frankfurt