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 [18]:
def round_down(n):
    s = str(n)
    if n <= 20:
        return n
    elif n < 100:
        return int(s[0] + '0'), int(s[1])
    elif n<1000:
        return int(s[0] + '00'),int(s[1]),int(s[2])

In [19]:
assert round_down(5) == 5
assert round_down(55) == (50,5)
assert round_down(222) == (200,2,2)

In [33]:
def number_to_words(n):
    """Given a number n between 1-1000 inclusive return a list of words for the number."""
    lst = []
    dic = {
        0: 'zero',
        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',
        100: 'one hundred',
        200: 'two hundred',
        300: 'three hundred',
        400: 'four hundred',
        500: 'five hundred',
        600: 'six hundred',
        700: 'seven hundred',
        800: 'eight hundred',
        900: 'nine hundred'}
    for i in range(1,n+1):
        if i <= 20:
            for entry in dic:
                if i == entry:
                     lst.append(dic[i])
        elif i < 100:
            first,second = round_down(i)
            for entry in dic:
                if first == entry:
                    if second == 0:
                        lst.append(dic[first])
                    else:
                        lst.append(dic[first] + '-' + dic[second])
        elif i <1000:
            first,second,third = round_down(i)
            for entry in dic:
                if first == entry:
                    if second == 0 and third == 0:
                        lst.append(dic[first])
                    elif second == 0:
                        lst.append(dic[first] + ' and ' + dic[third])
                    elif second == 1:
                        #For handling the teen case
                        lst.append(dic[first] + ' and ' + dic[int(str(second)+str(third))])
                    elif third == 0:
                        #Here I multiply by 10 because round_down removes the 0 for my second digit
                        lst.append(dic[first] + ' and ' + dic[second*10])
                    else:
                        lst.append(dic[first] + ' and ' + dic[second*10] + '-' + dic[third])
        elif i == 1000:
            lst.append('one thousand')
    return lst

In [34]:
number_to_words(5)


Out[34]:
['one', 'two', 'three', 'four', 'five']

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


In [35]:
assert len(number_to_words(5))==5
assert len(number_to_words(900))==900
assert number_to_words(50)[-1]=='fifty'

In [36]:
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 [37]:
def count_letters(n):
    """Count the number of letters used to write out the words for 1-n inclusive."""
    lst2 = []
    for entry in number_to_words(n):
        count = 0
        for char in entry:
            if char != ' ' and char != '-':
                count = count + 1
        lst2.append(count)
    return lst2

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


In [38]:
assert count_letters(1) == [3]
assert len(count_letters(342)) == 342
assert count_letters(5) == [3,3,5,4,4]

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

Finally used your count_letters function to solve the original question.


In [40]:
print(sum(count_letters(1000)))


21124

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

In [ ]: