Oban Numbers

October 1, 2010

Oban is a small town on the west coast of Scotland, home to a rocky port, a small distillery, and a half-built folly started by a banker with not-enough money and less sense. I fondly remember a visit to Oban in 1987. My mother bought a scarf, a tin of shortbread, and a wee dram of the local whiskey at a small shop on the main street (it may have been one of the shops in the picture, I’m not sure) and was scolded by the waitress for using the wrong fork at dinner. Oban numbers have nothing to do with Scotland, except that the name was the occasion of pleasant reminiscing.

MathWorld describes an oban number as a number from which the letter “o” is missing when it is spelled out in words (the letter “o” is “banned”).

Your task is to make a complete list of all the oban numbers. If your language provides a function that spells out a number in words, don’t use it, but write your own instead. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

6 Responses to “Oban Numbers”

1. […] Praxis – Oban Numbers By Remco Niemeijer In today’s Programming Praxis exercise, our task is to print a list of all Oban numbers (numbers that […]

2. Remco Niemeijer said

```obans :: [Int]
obans = filter (notElem 'o' . spell) [1..999] where
spell n | n <  20 = ones !! n
| n < 100 = tens !! div n 10 ++ spell (mod n 10)
| True    = spell (div n 100) ++ "hundred" ++ spell (mod n 100)
ones = "" : words "one two three four five six seven eight \
\nine ten eleven twelve thirteen fourteen \
\fifteen sixteen seventeen eighteen nineteen"
tens = "" : "" : words "twenty thirty forty fifty sixty \
\seventy eighty ninety"
tens = "" : "" : words "twenty thirty forty fifty sixty \
\seventy eighty ninety"

main :: IO ()
main = mapM_ print obans
```
3. Remco Niemeijer said

Whoops. Accidentally duplicated the tens definition. Here’s the correct version:

```obans :: [Int]
obans = filter (notElem 'o' . spell) [1..999] where
spell n | n <  20 = ones !! n
| n < 100 = tens !! div n 10 ++ spell (mod n 10)
| True    = spell (div n 100) ++ "hundred" ++ spell (mod n 100)
ones = "" : words "one two three four five six seven eight \
\nine ten eleven twelve thirteen fourteen \
\fifteen sixteen seventeen eighteen nineteen"
tens = "" : "" : words "twenty thirty forty fifty sixty \
\seventy eighty ninety"

main :: IO ()
main = mapM_ print obans
```
4. Sam said

— We don’t really need to spell them out, do we?

obanNumbers = filter (mkOban . show) [1..]

mkOban :: String -> Bool
mkOban [] = True
mkOban [‘1’,_] = True
mkOban (‘1’:_) = False
mkOban (‘2’:_) = False
mkOban (‘4’:_) = False
mkOban (x:xs) = mkOban xs

5. Iain said

Sam, I don’t think your version would print 11 or 12, which are oban numbers. I’m not sure, because I don’t read Haskell, though.

Here’s my Python version. It came out very similar to Remco’s version.

def int2str(num):
to_20 = [”, ‘one’, ‘two’, ‘three’, ‘four’, ‘five’, ‘six’, ‘seven’, ‘eight’,
‘nine’, ‘ten’, ‘eleven’, ‘twelve’, ‘thirteen’, ‘fourteen’,
‘fifteen’, ‘sixteen’, ‘seventeen’, ‘eighteen’, ‘nineteen’]
tens = [”, ”, ‘twenty’, ‘thirty’, ‘forty’, ‘fifty’, ‘sixty’, ‘seventy’,
‘eighty’, ‘ninety’]

if num < 20:
if num < 100:
return tens[num // 10] + ' ' + to_20[num % 10]
else:
return to_20[num // 100] + ' hundred ' + int2str(num % 100)

def oban():
return [i for i in range(1000) if int2str(i).find('o') == -1]

print oban()

6. Khanh said

Similarly, mine in F#

```let rec isOban(n : int) =
let digits = [""; "one"; "two"; "three"; "four"; "five";
"six"; "seven"; "eight"; "nine"; "ten"; "eleven";
"twelve";"thriteenth"; "fourteenth"; "fifteenth"; "sixteenth";
"seventeenth"; "eighteenth"; "nineteenth"]
let tens   = [""; ""; "twenty"; "thirty"; "fourty"; "fifty"; "sixty";"seventy"; "eighty";"ninety"]

if n < 20 then
not (digits.[n].Contains("o"))
elif n < 100 then
not(tens.[n/10].Contains("o")) && (isOban(n % 10))
elif n < 1000 then
not(digits.[n / 100].Contains("o")) && (isOban(n % 100))
else false

let l = List.filter isOban [1..1000] |> List.length

```