Tuesday, November 16, 2010

The next Project Euler problem I want to tackle is number 22:

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

The file in question contains data that looks like this:

"MARY","PATRICIA","LINDA","BARBARA",...

It's a nice list but I will need to clean it up to get it into a form that is easy to process. To that end I define a couple of helper functions. These allow me to use .NET's Regex class in a more functional manner:

open System.Text.RegularExpressions

let split pattern input =
    (new Regex(pattern)).Split(input)

let replace pattern (replacement:string) input =
    (new Regex(pattern)).Replace(input, replacement)

The value for a name is computed by adding the values for each letter ( a = 1, b = 2, c = 3, etc.). This is pretty easy in F# because a string can be treated as a sequence of characters. Thus the value of a name can be computed like this:

let value (name:string) =
    name |> Seq.map (fun c -> (int)c - (int)'A' + 1) |> Seq.sum

All the names in the file are already in uppercase so we don't have to do any normalisation there.

Once all the names have a value I need to compute a score for each name. This score is the name's value multiplied by its position in the alphabetically sorted list.

So, in words, here's what we do:
  1. Read in the names.
  2. Sanitize them by getting rid of the extraneous quotes.
  3. Split the resulting string into an array of name strings.
  4. Sort the array.
  5. Compute the score for each name.
  6. Sum the resulting scores.
  7. Display the result.
Using the previously defined functions this algorithm translates directly into F# code:

open System.IO

File.ReadAllText(@"e:\Project Euler\names.txt")
    |> replace "\"" ""
    |> split ","
    |> Array.sort
    |> Array.mapi (fun i name -> (i + 1)*(value name))
    |> Array.sum
    |> printfn "total = %A"

No comments: