60 Days of Euler in F# - Problem 42

The Problem

The nth term of the sequence of triangle numbers is given by, tn = ½n(n+1); so the first ten triangle numbers are:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

By converting each letter in a word to a number corresponding to its alphabetical position and adding these values we form a word value. For example, the word value for SKY is 19 + 11 + 25 = 55 = t10. If the word value is a triangle number then we shall call the word a triangle word.

Using words.txt (right click and 'Save Link/Target As...'), a 16K text file containing nearly two-thousand common English words, how many are triangle words?

The Solution

The most obvious place to start is by writing a function for tn

let t n = n * (n + 1) /2

Whew! I'm glad we got that complicated beasty out of the way.

Now, I suspect that we're going to be seeing the same triangle numbers over and over again, so I think it might be helpful to be able to find them quickly. Let's create a Map of the first 1000 triangle numbers.

let triangleNumbers = 
    Seq.unfold (fun state -> Some(t state, state + 1)) 1
    |> Seq.map (fun x -> (x,x))
    |> Seq.take 1000
    |> Map.ofSeq

And we can use that to create a function that determines if a given n is a triangle number.

let isTriangle n = Map.containsKey n triangleNumbers

Next, we need a way to turn a word into its numeric value, per the problem definition.

let toNumeric (s : string) =
    |> Seq.map (fun v -> int(v) - int('A') + 1)
    |> Seq.sum

string can be treated as Seq<char> so we simply map each character to its integer value, subtract the integer value for 'A', and add 1.

Now we can solve the problem:

let splitByMany (c : char[]) (s : string) = 
    s.Split(c, System.StringSplitOptions.RemoveEmptyEntries)

|> splitByMany [| '"'; ',' |]
|> Seq.map(fun w -> (w,toNumeric w))
|> Seq.filter (fun (w,v) -> isTriangle v)
|> Seq.length

The above reads in all the words, splits them into an array, computes their numeric value, filters out any values that aren't triangle numbers, and returns the sequence length. The length of the sequence is the answer.

Other Posts in This Series