3

So I was given a little task, I had to write a program in Python that prints a number's name from 0-999999.

But I ran into some problems, and I'd love to get your ideas and help.

This is what I have written so far:

numbers = {1: 'One', 2: 'Two', 3: 'Three', 4: 'Four', 5: 'Five', \
       6: 'Six', 7: 'Seven', 8: 'Eight', 9: 'Nine', 10: 'Ten', \
       11: 'Eleven', 12: 'Twelve', 13: 'Thirteen', 14: 'Fourteen', \
       15: 'Fifteen', 16: 'Sixteen', 17: 'Seventeen', 18: 'Eighteen', \
       19: 'Nineteen', 20: 'Twenty', 30: 'Thirty', 40: 'Forty', \
       50: 'Fifty', 60: 'Sixty', 70: 'Seventy', 80: 'Eighty', \
       90: 'Ninety', 0: 'Zero'}


def beta1(n):
    if n == 0:
        return numbers[0]
    elif n >= 1 and n <= 19:
        return numbers[n]
    elif n >= 20 and n <= 99:
        if n % 10 == 0:
            return numbers[n]
        else:
            return numbers[n - n % 10] + " " + numbers[n % 10]
    elif n>=100 and n<=999:
        if n%10 == 0:
            return numbers[n/100] + " Hundred"
        else:
            return numbers[n/100] + " Hundred" +" "  +numbers[n%100 - n %10] + " " + numbers[n % 10]
    elif n>=1000 and n<=999999:
        if n>= 1000 and n <=9999:
            if n%10 == 0:
                return numbers[n/1000] + " Thousand"
            else:
                return numbers[n/1000] + " Thousand" + " " +numbers[(n%1000- n%100)/100] + " Hundred " + numbers[n%100- n%10] + " " + numbers[n%10]

The problem is that I don't handle cases like this here:

beta1(5050):
Five Thousand
beta1(550):
Five Hundred
beta1(515):
Five Hundred Ten Five
beta1(505):
Five Hundred Zero Five

I would love to get some Ideas/help from you on this subject (with no libraries included, I want it to be purely coded.)

I am a fairly new coder so take it easy on me haha. Thanks in advance!

trizz
  • 57
  • 6
  • 1
    I would consider splitting to >1000 and <1000. Then use same logic for thousands and below thousands, just adding the word "thousands" o the former. – Aguy Jun 29 '16 at 20:08
  • You don't need the line continuation chars (`\\`) when defining the dictionary. – Brendan Abel Jun 29 '16 at 20:39

6 Answers6

1

You'll need to process each named group separately (Ex. Twenty-Four Thousand Four Hundred Fifty-One). Recursion will be your friend here so you won't have a long chain of if's

First off, you can short-circuit if the number provided is defined directly in your numbers dictionary, there's no need to check if the number is in a certain range

if num in numbers:
    return numbers[num]

Also, you should special case 0 and remove it from your numbers dictionary so we don't end up dividing by it later

if num == 0:
    return 'Zero'

I would define the different large quantifiers you're going to process

quantifiers = {
    10 ** 2: 'Hundred',
    10 ** 3: 'Thousand',
    10 ** 6: 'Million',
}

Then split up your number into the parts that will need to be processed separately.

num = 1234567

quantifier_amounts = []
r = num
for div in sorted(quantifiers.keys(), reverse=True):
    n, r = divmod(r, div)
    if n:
        quantifier_amounts.append((n, quantifiers[div]))
    if not r:
        break

This should give you

quantifier_amounts = [(1, 'Million'), (234, 'Thousand'), (5, 'Hundred')]
r = 67

Then, just process the leftover r value the same way using your numbers dictionary

amounts = []
if r:
    for div in sorted(numbers.keys(), reverse=True):
        n, r = divmod(r, div)
        if n:
            amounts.append(numbers[div])
        if not r:
            break

This should give you

amounts = ['Sixty', 'Seven']

Then recursively process each quantifier part and add the text together (the function is called numtext)

text = []
for n, name in quantifier_amounts:
    text.append('{} {}'.format(numtext(n), name))

if amounts:
    text.append('-'.join(amounts))

return ' '.join(text)

You should get

One Million Two Hundred Thirty-Four Thousand Five Hundred Sixty-Seven

Brendan Abel
  • 35,343
  • 14
  • 88
  • 118
0

You could handle large numbers by converting them to a string first and then parsing the string one character at a time. For example:

if n >= 1000:
    place = {1:'', 2:'', 3:'hundred', 4:'thousand'}
    return_val = ''
    n = str(n)
    while n != '':
        c = n[0]
        return_val += numbers[int(c)]
        return_val += place[len(n)]
        n = n[1:]

Obviously, this answer is not complete, but I think it would be the easiest way to solve this problem. Additionally, you could make recursive calls to your beta1 function in order to avoid heavily nested if-else statements.

Hope that helps!

mrwyatt
  • 183
  • 6
0

You are close! I would start with a top down approach (e.g. start on the 100000 level and work your way down) and use recursive calls. I would also use the % operator which represents mod (basically gives you remainder 5%2 = 1).

Here is an idea that will handle for example 5050:

numbers = {1: 'One', 2: 'Two', 3: 'Three', 4: 'Four', 5: 'Five', \
   6: 'Six', 7: 'Seven', 8: 'Eight', 9: 'Nine', 10: 'Ten', \
   11: 'Eleven', 12: 'Twelve', 13: 'Thirteen', 14: 'Fourteen', \
   15: 'Fifteen', 16: 'Sixteen', 17: 'Seventeen', 18: 'Eighteen', \
   19: 'Nineteen', 20: 'Twenty', 30: 'Thirty', 40: 'Forty', \
   50: 'Fifty', 60: 'Sixty', 70: 'Seventy', 80: 'Eighty', \
   90: 'Ninety', 0: 'Zero'}

mapping = {3:'Hundred', 4:'Thousand', ...}

def beta1(n):
    numofdigits = len(n)
    if not mapping[numofdigits]:
        use your own code
    else:
        divider = (10 ** (numofdigits))
        word = numbers[n/divider]
        remainder = n%divider
        return word + mapping[numofdigits] + beta1(remainder)

For example, if I plug in 5050 into this function. It will do the integer division of 5050 and 10^len(5050), i.e. 5050/1000 which gives you five. The remainder from 5050%1000 is 50. Now the function returns word, which in this case would be 'Five' and concatenates with mapping[4] which is 'Thousand' + a recursive call to your function for parsing 50 which would return 'Fifty'. Therefore your final result would be 'Five Thousand Fifty'.

This is a more elegant solution as you don't have to really hard code much. I'll let you handle the other cases! Good luck, let me know if you have any more questions.

Tonechas
  • 13,398
  • 16
  • 46
  • 80
Jason
  • 86
  • 1
  • 9
0

I'll not give you a straight answer, but hints.

First of all you need to parse numbers in groups of three digits as it is exactly the same wording for each group of 3, the only difference is suffix that describe "level", eg:

505 and 505,000 will be basically the same: "five hundreds and five" where on second you just need to add "thousands"

this implies, that you need to have one more table:

suffixes = ['', 'thousand', 'million', ...]

(first level is empty)

then parsing each triplet is simple: - check for hundreds number // 100, get for this digit entry from numbers - remainder - if is less than 20 - get from the numbers, otherwise, get first digit (number//10 * 10) fetch from numbers add "hundred(s)" and fetch reminder (number%10) from numbers - do not forget to add "s" to the end of suffixes

Jerzyk
  • 3,662
  • 23
  • 40
0

Brenden Abel's answer above is pretty good, but here's a nice and tight, more self-contained version. As others have pointed out, recursion is your friend here:

def beta1(n, returnZero=True):
    if n == 0 and not returnZero: return []             # Prevent superfluous final "zero", e.g. 2900: "two thousand nine hundred zero"
    if n in numbers: return [numbers[n]]                # Direct mapping from n to text
    if n >= 1000: return beta1(n // 1000) + ['Thousand'] + beta1(n%1000, False)
    if n >= 100: return beta1(n // 100) + ['Hundred'] + beta1(n%100, False)
    if n > 20: return [numbers[n//10*10]] + beta1(n%10, False)

# This function returns the elements as a list, so convert it to a string:
print( " ".join(beta1(12345)) )

Of course, this can easily be extended to handle numbers greater than 999,999:

    if n >= 1000000000: return beta1(n // 1000000000) + ['Billion'] + beta1(n%1000000000, False)
    if n >= 1000000: return beta1(n // 1000000) + ['Million'] + beta1(n%1000000, False)

And, a few test cases:

# Wrapper function that converts from a list to a string
# def beta1Text(n): return " ".join(beta1(n))
def beta1Text(n): return " ".join(beta1(n))

# Your test cases
print(beta1Text(5050))      # Five Thousand Fifty
print(beta1Text(550))       # Five Hundred Fifty
print(beta1Text(515))       # Five Hundred Fifteen
print(beta1Text(505))       # Five Hundred Five

# A few more test cases
print(beta1Text(290000))    # Two Hundred Ninety Thousand
print(beta1Text(123210))    # One Hundred Twenty Three Thousand Two Hundred Ten
print(beta1Text(990000))    # Nine Hundred Ninety Thousand
print(beta1Text(123456))    # One Hundred Twenty Three Thousand Four Hundred Fifty Six
for ii in range(20): print(beta1Text(ii))   # Zero, One, Two...Eighteen, Nineteen

# Test cases > 999,999
print(beta1Text(1000000))       # One Million
print(beta1Text(1000000000))    # One Billion
print(beta1Text(1234567898))    # One Billion Two Hundred Thirty Four Million Five Hundred Sixty Seven Thousand Eight Hundred Ninety Eight
CrackaJackDev
  • 121
  • 1
  • 4
-2

This may seem tedious, but convert each place into an individual number then add the strings of the words. I have done up to 999 in a few minutes. Continue the same pattern and it should be easy and very basic!

numbers = {1: 'One', 2: 'Two', 3: 'Three', 4: 'Four', 5: 'Five', \
   6: 'Six', 7: 'Seven', 8: 'Eight', 9: 'Nine', 10: 'Ten', \
   11: 'Eleven', 12: 'Twelve', 13: 'Thirteen', 14: 'Fourteen', \
   15: 'Fifteen', 16: 'Sixteen', 17: 'Seventeen', 18: 'Eighteen', \
   19: 'Nineteen', 20: 'Twenty', 30: 'Thirty', 40: 'Forty', \
   50: 'Fifty', 60: 'Sixty', 70: 'Seventy', 80: 'Eighty', \
   90: 'Ninety', 0: ''}


def beta1(n):
    global numbers
    if n == 0:
        pass
    elif n <= 20:
        return numbers[n]
    elif 10 < n < 100:
        tens = int(str(n)[0]) * 10
        ones = int(str(n)[1])
        return numbers[tens] + " " + numbers[ones]
    elif 100 < n < 1000:
        hundreds = int(str(n)[0])
        tens = int(str(n)[1]) * 10
        ones = int(str(n)[2])
        return numbers[hundreds] + " Hundred " + numbers[tens] + " "+ numbers[ones]

for n in range(1000):
    print beta1(n)
Tonechas
  • 13,398
  • 16
  • 46
  • 80
yarz-tech
  • 284
  • 2
  • 6
  • 18