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 [1]:
def number_to_words(n):
    """Given a number n between 1-1000 inclusive return a list of words for the number."""
    n=str(n)
    key = {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'}
    if len(n)==4:                                                   # '1000'
        return 'one thousand'
    elif len(n)==3:                                                 # 3-digit numbers
        if int(n[1])==0 and int(n[2])==0:                           # 'n00' 
            return key[int(n[0])]+' hundred'
        elif int(n[1])==0 and not int(n[2])==0:                     # 'n0l'
            return key[int(n[0])]+' hundred and '+key[int(n[2])]
        elif not int(n[1])==0 and int(n[2])==0:                     # 'nm0'
            return key[int(n[0])]+' hundred and '+key[int(n[1])*10]
        elif not int(n[1])==0 and not int(n[2])==0:                 # 'nml'
            if int(n[1])==1:                                        # 'n1l'
                return key[int(n[0])]+' hundred and '+key[int(n[1]+n[2])]
            elif not int(n[1])==1:
                return key[int(n[0])]+' hundred and '+key[int(n[1])*10]+'-'+key[int(n[2])]
    elif len(n)==2:                                                 # 2-digit numbers
        if int(n[1])==0:                                            # 'n0'
            return key[int(n[0])*10]
        elif not int(n[1])==0:                                      # 'nm'
            if int(n[0])==1:                                        # '1m'
                return key[int(n[0]+n[1])]
            elif not int(n[0])==1:
                return key[int(n[0])*10]+'-'+key[int(n[1])]
    elif len(n)==1:                                                 # 1-digit numbers
        return key[int(n)]

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


In [2]:
p = range(1,11)
type(p)


Out[2]:
range

In [3]:
assert number_to_words(1000)=='one thousand'
assert number_to_words(593)=='five hundred and ninety-three'
assert number_to_words(111)=='one hundred and eleven'
assert number_to_words(67)=='sixty-seven'
assert number_to_words(14)=='fourteen'
assert number_to_words(2)=='two'

In [4]:
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 [5]:
l="I am a-string"
len(''.join(l.split()))


Out[5]:
11

In [6]:
def count_letters(n):
    """Count the number of letters used to write out the words for 1-n inclusive."""
    phi = number_to_words(n)
    count = len(''.join(phi.split()))
    for i in range(len(phi)):
        if phi[i]=='-':
            count -= 1
    return count

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


In [7]:
assert count_letters(1000)==11
assert count_letters(342)==23
assert count_letters(115)==20
assert count_letters(21)==9

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

Finally used your count_letters function to solve the original question.


In [9]:
total=0
for i in range(1,1001):
    total += count_letters(i)
total


Out[9]:
21124

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