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.


In [138]:
let units = [
    ""
    "one"
    "two"
    "three"
    "four"
    "five"
    "six"
    "seven"
    "eight"
    "nine"
]

let teens = [
    "ten"
    "eleven"
    "twelve"
    "thirteen"
    "fourteen"
    "fifteen"
    "sixteen"
    "seventeen"
    "eighteen"
    "nineteen"
]

let tens = [
    ""
    "ten"     // handled in "teens" case, probably not needed?
    "twenty"
    "thirty"
    "forty"
    "fifty"
    "sixty"
    "seventy"
    "eighty"
    "ninety"
]

let hundred = "hundred"

let thousand = "thousand"

let breakNumberIntoPowerParts n =
    let numberByPowerPosition =
        n.ToString().ToCharArray() 
        |> Array.map (fun x -> int(string(x)))
        |> Array.rev
    
    seq {
        for i = 0 to numberByPowerPosition.Length - 1 do
            yield (i, (numberByPowerPosition.[i]))
    }
    |> Seq.toList
    |> List.rev

let simpleStringify pow10 n = 
    match pow10 with
    | 3 -> units.[n] + thousand
    | 2 -> if n > 0 then units.[n] + hundred else ""
    | 1 -> tens.[n]
    | 0 -> units.[n]  
    | _ -> ""
    
let rec stringifyPowerParts (digitPairs:(int * int) list) =     
    if digitPairs.IsEmpty then [] else
        let (pow10, n) = List.head digitPairs
        if pow10 = 1 && n = 1 then [teens.[snd(List.head(List.tail digitPairs))]; ""]
        else [(simpleStringify pow10 n)] @ (stringifyPowerParts (List.tail digitPairs))

let maybeInsertAnd (numList:string list) =
    if numList.Length < 3 then numList // no "and" needed, number < 100
    else
        let revNumList = List.rev numList
        let unitAndTen = revNumList.[0..1]
        let allTheRest = revNumList.[2..(revNumList.Length-1)]
        
        if revNumList.[0] <> "" || revNumList.[1] <> "" then
            (unitAndTen @ ["and"] @ allTheRest)
            |> List.rev
        else numList

let countEnglishLongForm n =
    breakNumberIntoPowerParts n
    |> stringifyPowerParts 
    |> maybeInsertAnd
    |> List.filter (fun s -> s <> "")
    |> String.concat ""
    |> String.length
    
[1..1000]
|> List.map countEnglishLongForm
|> List.sum


Out[138]:
21124

In [ ]: