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 [85]:
def number_to_words(n):
    """Given a number n between 1-1000 inclusive return a list of words for the number."""
    words = {0:'',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'}
    if n<20:
        return words[n]
    elif n>=20 and n<30:
        return 'twenty'+ words[(n-20)]
    elif n>=30 and n<40:
        return 'thirty'+ words[(n-30)]
    elif n>=40 and n<50:
        return 'forty'+ words[(n-40)]
    elif n>=50 and n<60:
        return 'fifty'+ words[(n-50)]
    elif n>=60 and n<70:
        return 'sixty'+ words[(n-60)]
    elif n>=70 and n<80:
        return 'seventy'+ words[(n-70)]
    elif n>=80 and n<90:
        return 'eighty'+ words[(n-80)]
    elif n>=90 and n<100:
        return 'ninety'+ words[(n-90)]
    elif n%100==0 and n<1000:
        return words[n/100] + 'hundred'
    elif n>100 and n<1000:
        i = n%100
        x=0
        if i<20:
            x=words[i]
        elif i>=20 and i<30:
            x= 'twenty'+ words[(i-20)]
        elif i>=30 and i<40:
            x= 'thirty'+ words[(i-30)]
        elif i>=40 and i<50:
            x= 'forty'+ words[(i-40)]
        elif i>=50 and i<60:
            x= 'fifty'+ words[(i-50)]
        elif i>=60 and i<70:
            x= 'sixty'+ words[(i-60)]
        elif i>=70 and i<80:
            x= 'seventy'+ words[(i-70)]
        elif i>=80 and i<90:
            x= 'eighty'+ words[(i-80)]
        elif i>=90 and i<100:
            x= 'ninety'+ words[(i-90)]
        return words[(n-n%100)/100] + 'hundred' + 'and' + x
    elif n==1000:
        return 'onethousand'

I realize this probably isn't the fastest or most concise code, but it works.

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


In [86]:
assert number_to_words(25)=='twentyfive'
assert number_to_words(467)=='fourhundredandsixtyseven'
assert number_to_words(1000)=='onethousand'
assert number_to_words(1)=='one'
assert number_to_words(30)=='thirty'

In [87]:
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 [88]:
def count_letters(n):
    """Count the number of letters used to write out the words for 1-n inclusive."""
    x=n
    count=0
    while x>0:
        count += len(number_to_words(x))
        x -= 1
    return count

Someone can probably do this in less lines but this method makes the most sense to me.

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


In [89]:
assert count_letters(1)==3
assert count_letters(3)==11
assert count_letters(10)==39

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

Finally used your count_letters function to solve the original question.


In [92]:
count_letters(1000)


Out[92]:
21124

Success!


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