# Text representation for numbers with python

Simple function which returns a text representation for numbers in range [1...1000].

N100 = 'hundred'
N1000 = 'one thousand'
N1_9 = [
'one', 'two', 'three',
'four', 'five', 'six',
'seven', 'eight', 'nine',
]
N10_19 = [
'ten', 'eleven', 'twelve',
'thirteen', 'fourteen', 'fifteen',
'sixteen', 'seventeen', 'eighteen',
'nineteen',
]
Nx10 = [
'twenty', 'thirty', 'forty',
'fifty', 'sixty', 'seventy',
'eighty', 'ninety',
]

def make_word(num):
assert 0 < num <= 1000
if num == 1000:
return N1000
lst = [0] * 3
for i in xrange(3):
div = 10 ** (2 - i)
lst[i] = num / div
num %= div
res = []
if lst[0] != 0:
res.append(
'{} {}'.format(N1_9[lst[0]-1], N100)
)
if lst[1] or lst[2]:
if lst[1] == 0:
res.append(
N1_9[lst[2] - 1]
)
elif lst[1] == 1:
res.append(
N10_19[lst[2]]
)
else:
if lst[2] == 0:
res.append(
Nx10[lst[1] - 2]
)
else:
res.append(
'{}-{}'.format(Nx10[lst[1] - 2], N1_9[lst[2] - 1])
)
return ' and '.join(res)

for x in xrange(1, 1000 + 1):
print x, make_word(x)


Is it possible to rewrite the function a little bit cleaner? Maybe decrease a number of branches somehow

rewrite the function a little bit cleaner

A way to achieve it, would be to divide your code into simpler functions, for instance:

lst = [0] * 3
for i in xrange(3):
div = 10 ** (2 - i)
lst[i] = num / div
num %= div


Could be a simple function call:

lst = split_decimals(num)


(btw the name lst is not a very explicit...)

Maybe decrease a number of branches somehow

To clean your branching, I would advise to make a function that treats one part of the problem: numbers between 1 and 99, with a function under_hundred_as_word for instance.

Better variable names might also help the reader to understand your code.

After some further refactoring, this is what I came with:

units = [
'zero', 'one', 'two', 'three',
'four', 'five', 'six',
'seven', 'eight', 'nine',
]
tens = [
'', '', 'twenty', 'thirty', 'forty',
'fifty', 'sixty', 'seventy',
'eighty', 'ninety',
]

hundred_exceptions = {
10: 'ten',
11: 'eleven',
12: 'twelve',
13: 'thirteen',
15: 'fifteen',
18: 'eighteen',
}

def under_hundred_as_word(num):
assert 0 < num < 100

unit = num % 10
ten = num / 10
if ten == 0:
return units[unit]
elif ten == 1:
if num in hundred_exceptions:
return hundred_exceptions[num]
else:
return units[unit] + 'teen'
else:
if unit:
return tens[ten] + '-' + units[unit]
else:
return tens[ten]

def make_word(num):
assert 0 < num <= 1000
if num == 1000:
return 'one thousand'

parts = []

# two last digits
if num % 100:
parts.insert(0, under_hundred_as_word(num % 100))

# hundred digit
hundreds = (num / 100) % 10
if hundreds:
hundreds = units[hundreds] + ' hundred'
parts.insert(0, hundreds)

return ' and '.join(parts)

for x in xrange(1, 1000 + 1):
print x, make_word(x)


It can be easily modified to print numbers greater than 1000.