Project Euler: Problem 17

https://projecteuler.net/problem=17

If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.

If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?

NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage.

First write a number_to_words(n) function that takes an integer n between 1 and 1000 inclusive and returns a list of words for the number as described above


In [98]:
#First I define a dictionary of all the necessary words to make numbers
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:''}
#print (numbers[11])
numword = ''
def number_to_words(n):
    """Given a number n between 1-1000 inclusive return a list of words for the number."""
    numword = ''
    n = str(n)    
    if 99 < int(n) < 1000 and int(n)%100 != 0:  #In this range the hundreds place is added to the string and removed from n
        numword = numbers[int(n[0])] + 'hundredand'
        n = n[1:]
    elif 99 < int(n) < 1000 and int(n)%100 == 0:  #There is a special case for exact 100's
        numword = numbers[int(n[0])] + 'hundred'
        n = '0'
    elif int(n) == 1000:  #I could have programmed in a section for the thousands but I felt it sufficient to make it a special case
        numword = 'onethousand'
    if int(n) < 20:
        numword = numword + numbers[int(n)]
    elif 19 < int(n) < 100:
        numword = numword + numbers[int(n[0] + '0')] + numbers[int(n[1])] 
    return numword

Now write a set of assert tests for your number_to_words function that verifies that it is working as expected.


In [99]:
assert number_to_words(14) == 'fourteen'
assert number_to_words(458) == 'fourhundredandfiftyeight'  #It made more sense to me to make a single space-free word
#raise NotImplementedError()

In [100]:
assert True # use this for grading the number_to_words tests.

Now define a count_letters(n) that returns the number of letters used to write out the words for all of the the numbers 1 to n inclusive.


In [94]:
def count_letters(n):
    """Count the number of letters used to write out the words for 1-n inclusive."""
    return len(number_to_words(n))

Now write a set of assert tests for your count_letters function that verifies that it is working as expected.


In [95]:
assert count_letters(342) == 23 
assert count_letters(115) == 20 
#raise NotImplementedError()

In [72]:
assert True # use this for grading the count_letters tests.

Finally used your count_letters function to solve the original question.


In [97]:
n = 0
x = 0
while n < 1000:
    n = n + 1
    x = x + count_letters(n)
print(x)
#raise NotImplementedError()


21124

In [54]:
assert True # use this for gradig the answer to the original question.