Another day flown by… another Euler problem to tease me… today I attempted problem 9.
The Problem
A Pythagorean triplet is a set of three natural numbers, a < b < c, for which a^2 + b^2 = c^2
For example, 3^2 + 4^2 = 9 +16 = 25 = 5^2.
There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc.
The Solution
Initially I thought I would try and tackle this problem by setting up 3DArrays in F#, thus my question on StackOverflow regarding 2D Array.
However, if I used the arrays I would not be able to use the handy Seq methods. After some more thinking, I decided to use tuples instead and generate the permutations using the Seq.unfold method.
let generatePossibleCandidates =
(1,1)
|> Seq.unfold(fun (x,y) ->
let z = TargetResult - (x+y)
let xyz = x*y*z
if (y>TargetResult) then None
else if (x>=y-1) then Some((Square(x),Square(y),Square(z),xyz), (1,y+1))
else Some((Square(x),Square(y),Square(z),xyz), (x+1,y))
)
I must be honest I am not to happy with the formatting of this code… it looks a bit clunky and messy… but it did the trick for now. Once I had all possible permutations generated, filtering the result was relatively simple.
let FilterCandidates data =
data |> Seq.filter(fun (x,y,z,r) -> (x+y=z))
|> Seq.filter(fun (x,y,z,r) -> (x<y) && (y<z))
|> Seq.iter(fun x ->
let (a,b,c,d) = x
printfn "%f" (Math.Sqrt(a|>float))
printfn "%f" (Math.Sqrt(b|>float))
printfn "%f" (Math.Sqrt(c|>float))
printfn "%d" d
()
)
The entire solution looked like this…
open System
let TargetResult = 1000
let Square x = x*x
///
/// Generate all permutations, by producing squares of x & y with z being the
/// targetresult - the sum of x & y
///
let generatePossibleCandidates =
(1,1)
|> Seq.unfold(fun (x,y) ->
let z = TargetResult - (x+y)
let xyz = x*y*z
if (y>TargetResult) then None
else if (x>=y-1) then Some((Square(x),Square(y),Square(z),xyz), (1,y+1))
else Some((Square(x),Square(y),Square(z),xyz), (x+1,y))
)
///
/// Filter permutation by reducing the collection by the
/// problem criteria.
///
let FilterCandidates data =
data |> Seq.filter(fun (x,y,z,r) -> (x+y=z))
|> Seq.filter(fun (x,y,z,r) -> (x<y) && (y<z))
|> Seq.iter(fun x ->
let (a,b,c,d) = x
printfn "%f" (Math.Sqrt(a|>float))
printfn "%f" (Math.Sqrt(b|>float))
printfn "%f" (Math.Sqrt(c|>float))
printfn "%d" d
()
)
FilterCandidates generatePossibleCandidates
I understand that there are some algebraic approaches to solving this problem, but I found the brute force approach to be performant enough for me not to worry about it any further….