Project Euler — Problem 22 Solution


Using names.txt (right click and ‘Save Link/Target As…’), a 46K text file con­tain­ing over five-thou­sand first names, begin by sort­ing it into alpha­bet­i­cal order. Then work­ing out the alpha­bet­i­cal val­ue for each name, mul­ti­ply this val­ue by its alpha­bet­i­cal posi­tion in the list to obtain a name score.

For exam­ple, when the list is sort­ed into alpha­bet­i­cal order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 x 53 = 49714.

What is the total of all the name scores in the file?


open System.IO

let values =
    |> (fun s -> s.Replace("\"", ""))
    |> Array.collect (fun s -> s.Trim().Split(','))
    |> Array.sort
    |> (fun s -> s.ToUpper().ToCharArray() |> Array.sumBy (fun c -> int32(c) - (int32('A') - 1)))

let answer = Array.map2 (fun v p -> v * p) values [|1..values.Length|] |> Array.sum

Once I’ve down­loaded the names.txt file and loaded its con­tents in, the first thing I need­ed to do was to remove the dou­ble quotes and split the remain­ing strings by com­ma to get back a string array of the names, e.g.:


Now that the data is in a use­ful for­mat I can eas­i­ly sort it and then do the nec­es­sary com­pu­ta­tion to work out the score for each name. Let me draw your atten­tion to the func­tion in the Array.sumBy func­tion:

Array.sumBy (fun c -> int32(c) - (int32('A') - 1))

As I’ve men­tioned in the prob­lem 8 solu­tion, int32(char) returns the uni­code val­ue of the char, which in this case is the alpha­bet­i­cal val­ue we need to cal­cu­late the score for a name. But we can’t just use it as it is, because the char sequence A, B, C… does not start at 1, which is why we need to work out the off­set using int32(‘A’) – 1.

Final­ly, the Array.map2 func­tion is sim­i­lar to, except that it works on two arrays at a time. So here I’m trans­form­ing the array of alpha­bet­i­cal val­ues (for the sort­ed names) and the array of cor­re­spond­ing alpha­bet­i­cal orders into the score for each name before I add them all up to get the answer.