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 [2]:
def number_to_words(n):
    """Given a number n between 1-1000 inclusive return a list of words for the number."""
    _1={1:' ',2:"-"}
    _9={1:"one",2:"two",3:"three",4:"four",5:'five',6:'six',7:'seven',8:"eight",9:'nine',0:'',11:'and'}
    _100={0:'',1:'ten',2:"twenty",3:'thirty',4:'forty',5:'fifty',6:'sixty',7:'seventy',8:'eighty',9:'ninety',10:'hundred'}
    _19={1:'eleven',2:'twelve',3:'thirteen',4:'fourteen',5:'fifteen',6:'sixteen',7:'seventeen',8:'eighteen',9:'nineteen'}
    #above creates all the needed combinations for up to 999 and below makes 1000
    str_n=str(n)
    x=int(str_n[0])
    if n==1000:
        first,second,third='one thousand','',''
    elif len(str_n)==3: # takes care of all numbers from 100-999 
        if int(str_n[1:3])>10 and int(str_n[1:3])<20: # writes for x11-x19
            z=int(str_n[2])
            first,second,third=_9[x]+_1[1]+_100[10]+_1[1]+_9[11],' ',_19[z]    
        elif int(str_n[2])==0 and int(str_n[1])==0: #writes for 100,200,300,...
            first,second,third=_9[x]+_1[1]+_100[10],'',''
        else:
            y,z=int(str_n[1]),int(str_n[2])#writes for all other numbers of length 3
            first,second,third=_9[x]+_1[1]+_100[10]+_1[1]+_9[11]+_1[1],_100[y],_9[z]
    elif len(str_n)==2: #takes care of 10-99
        if n>10 and n<20: # writes for 11-19
            y=int(str_n[1])
            first,second,third='','',_19[y]
        else:  #writes everything else
            y=int(str_n[1])
            first,second,third='',_100[x],_9[y]
    else: #writes for 0-9
        first,second,third='','',_9[x]
    answer=first+second+third
    return answer

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


In [3]:



thirtynine

In [120]:
assert number_to_words(333)=="three hundred and thirtythree"
assert number_to_words(21)=='twentyone'
assert number_to_words(20)=='twenty'
assert number_to_words(19)=='nineteen'
assert number_to_words(219)=='two hundred and nineteen'
assert number_to_words(1)=='one'
assert number_to_words(1000)=='one thousand'
assert number_to_words(101)=='one hundred and one'
assert number_to_words(180)=='one hundred and eighty'
assert number_to_words(100)=='one hundred'

In [121]:
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 [123]:
def count_letters(n):
    """Count the number of letters used to write out the words for 1-n inclusive."""
    numbers=[i for i in range(1,n+1)]
    l=[number_to_words(i) for i in numbers]
    f=''.join(l)
    f1=f.replace(' ','')
    f2=f1.replace('-','')
    return len(f2)

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


In [124]:
assert count_letters(1)==3
assert count_letters(5)==19
assert count_letters(10)==39
assert count_letters(115)-count_letters(114)==20

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

Finally used your count_letters function to solve the original question.


In [126]:
count_letters(1000)


Out[126]:
21124

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