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 [31]:
def number_to_words(n):
    """Given a number n between 1-1000 inclusive return a list of words for the number."""
    x = []
    a = {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'}
    b = 'hundred'
    c = 'thousand'
    d = 'and'
    if n <= 20 and n >= 1:
        x.append(a[n])
        return x
    elif n > 20 and n < 100:
        if n % 10 == 0:
            x.append(a[n])
            return x
        else:
            y = str(n)
            x.append(a[int(y[0] + '0')])
            x.append(a[int(y[1])])
            return x
    elif n >= 100 and n < 1000:
        if n % 100 == 0:
            y = str(n)
            x.append(a[int(y[0])])
            x.append(b)
            return x
        elif n % 10 == 0:
            y = str(n)
            x.append(a[int(y[0])])
            x.append(b)
            x.append(d)
            x.append(a[int(y[1]+'0')])
            return x
        elif str(n)[1] == '0':
            y = str(n)
            x.append(a[int(y[0])])
            x.append(b)
            x.append(d)
            x.append(a[int(y[2])])
            return x
        elif str(n)[1] == '1':
            y = str(n)
            x.append(a[int(y[0])])
            x.append(b)
            x.append(d)
            x.append(a[int(y[1]+y[2])])
            return x
        else:
            y = str(n)
            x.append(a[int(y[0])])
            x.append(b)
            x.append(d)
            x.append(a[int(y[1]+'0')])
            x.append(a[int(y[2])])
            return x
    else:
        x.append(a[1])
        x.append(c)
        return x

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


In [34]:
assert number_to_words(16) == ['sixteen']
assert number_to_words(507) == ['five','hundred','and','seven']
assert number_to_words(735) == ['seven', 'hundred', 'and', 'thirty', 'five']
assert len(''.join(number_to_words(342))) == 23

In [35]:
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 [36]:
def count_letters(n):
    """Count the number of letters used to write out the words for 1-n inclusive."""
    z = 0
    x = range(1,n+1)
    for m in x:
        j = number_to_words(m)
        k = len(''.join(j))
        z += k
    return z

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


In [37]:
assert count_letters(6) == 22

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

Finally used your count_letters function to solve the original question.


In [39]:
count_letters(1000)


Out[39]:
21124

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