HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Python converter: number-to-English - Project Euler 17

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
numberenglishprojectpythoneulerconverter

Problem

So I wrote this function to convert a given number to its interpretation in the English language as part of the Project Euler exercises. It works fine, but I sense that it's rather sloppy and inelegant, especially for Python where many things can be done quickly in a couple of lines. Any feedback on how to make this code more beautiful/Pythonic is appreciated!

NUMBER_WORDS = {
    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"
}

def convert_number_to_words(num):
    #Works up to 99,999
    num = str(num)
    analyze = 0
    postfix = remainder = None
    string = ""
    if len(num) > 4:
        analyze = int(num[0:2])
        remainder = num[2:]
        postfix = " thousand "
    elif len(num) > 3:
        analyze = int(num[0:1])
        remainder = num[1:]
        postfix = " thousand "
    elif len(num) > 2:
        analyze = int(num[0:1])
        remainder = num[1:]
        postfix = " hundred "
        if int(remainder) > 0:
            postfix += "and "
    elif int(num) in NUMBER_WORDS:
        analyze = int(num)
    else:
        analyze = int(num[0:1] + "0")
        remainder = num[1:]
        postfix = "-"
    string = NUMBER_WORDS[analyze]
    if postfix is not None:
        string += postfix
    if remainder is not None and int(remainder) > 0:
        return string + convert_number_to_words(remainder)
    else:
        return string

Solution

Here's one using modulo % and list joining that uses your original NUMBER_WORDS dict:

def int_to_english(n):
    english_parts = []
    ones = n % 10
    tens = n % 100
    hundreds = math.floor(n / 100) % 10
    thousands = math.floor(n / 1000)

    if thousands:
        english_parts.append(int_to_english(thousands))
        english_parts.append('thousand')
        if not hundreds and tens:
            english_parts.append('and')
    if hundreds:
        english_parts.append(NUMBER_WORDS[hundreds])
        english_parts.append('hundred')
        if tens:
            english_parts.append('and')
    if tens:
        if tens < 20 or ones == 0:
            english_parts.append(NUMBER_WORDS[tens])
        else:
            english_parts.append(NUMBER_WORDS[tens - ones])
            english_parts.append(NUMBER_WORDS[ones])
    return ' '.join(english_parts)


It works up to 999,999, but could be extended further with a little customisation.

Code Snippets

def int_to_english(n):
    english_parts = []
    ones = n % 10
    tens = n % 100
    hundreds = math.floor(n / 100) % 10
    thousands = math.floor(n / 1000)

    if thousands:
        english_parts.append(int_to_english(thousands))
        english_parts.append('thousand')
        if not hundreds and tens:
            english_parts.append('and')
    if hundreds:
        english_parts.append(NUMBER_WORDS[hundreds])
        english_parts.append('hundred')
        if tens:
            english_parts.append('and')
    if tens:
        if tens < 20 or ones == 0:
            english_parts.append(NUMBER_WORDS[tens])
        else:
            english_parts.append(NUMBER_WORDS[tens - ones])
            english_parts.append(NUMBER_WORDS[ones])
    return ' '.join(english_parts)

Context

StackExchange Code Review Q#39183, answer score: 4

Revisions (0)

No revisions yet.