First of all I apologize if the title of this is misleading, its based off what I think my issue might be. I am creating a lazy list of tuples, the end goal is to find all pythagorean triples with values less than or equal to n and rather than create all possible combination of 'triples', I have gone for this approach which I think is more efficient but might be overkill, however, it works :)
val n = 20
val increasingTriplets = unfold(Option(1, 1, 1)) {
case None => None
case Some(current) =>
val maybeNext = current match {
case (`n`, `n`, `n`) => None
case (x, `n`, `n`) => Some(x + 1, x + 1, x + 1)
case (x, y, `n`) => Some(x, y + 1, y + 1)
case (x, y, z) => Some(x, y, z + 1) // (1,1,1) , (1,1,2), (1,1,3)...etc
}
Some(current, maybeNext)
}.take(nCr(`n`+3-1,3).toInt).filter({ // The formula for the number of combinations with repetition -
case (a,b,c) => a*a + b*b == c*c // - allowed of objects from types is +−1C
// Ensures minimum number of lists is always generated(I think)
})
println(unfold_with_pythcomp(increasingTriplets,pythcomp).toList)
// n = 20 List((3,4,5), (4,3,5), (5,12,13), (12,5,13), (6,8,10)
List((3,4,5), (4,3,5), (5,12,13), (12,5,13), (6,8,10), (8,6,10),
(8,15,17), (15,8,17), (9,12,15), (12,9,15), (12,16,20), (16,12,20))
// n = 10
List((3,4,5), (4,3,5), (6,8,10), (8,6,10))
// Implementation of unfold
def unfold[A, S](z: S)(f: S => Option[(A, S)]): LazyList[A] =
f(z).map((p: (A, S)) => p._1 #:: unfold(p._2)(f)).getOrElse(LazyList.empty[A])
def unfold_with_pythcomp[A](l1: LazyList[A], f: A => Option[(A, A)]): LazyList[A] =
// unfolds result list appending the "complement"
l1 match {
case LazyList() => l1
case x #:: y => f(x) match {
case Some((l, r)) => l #:: r #:: unfold_with_pythcomp(y, f)
}
}
def pythcomp(t: (Int, Int, Int)): Option[((Int, Int, Int), (Int, Int, Int))] = t match {
//Creates a "complement" to add since (3,4,5) <-> (4,3,5)
case (a, b, c) => Some((a, b, c), (b, a, c))
}
def fact(n: Int): BigInt = { // These are just for efficiency, you may ignore
@tailrec def go(n: Int, acc: BigInt): BigInt =
if (n <= 0) acc
else go(n - 1, BigInt(n) * acc)
go(n, 1)
}
def nCr(n: Int, r: Int): BigInt = { // These are just for efficiency, you may ignore
fact(n)/(fact(n-r) * fact(r))
}
Now I am trying to make this into a function that would do the exact same thing while taking just n as an argument which might be really simple, however I have been running into issues trying to pattern match the given n argument. This is what I came up with so far:
def unfold_remix[Int](`n`: Int): LazyList[Option[(Int, Int, Int)]] =
// not sure if I can use backticks here
unfold(Option(1, 1, 1)) {
case None => None
case Some(current) =>
// Problem could also be from here.
val maybeNext = current match {
case (`n`, `n`, `n`) => None
case (x, `n`, `n`) => Some(x + 1, x + 1, x + 1)
case (x, y, `n`) => Some(x, y + 1, y + 1)
case (x, y, z) => Some(x, y, z + 1) // (1,1,1) , (1,1,2), (1, 1,3)...1st
}
Some(current, **maybeNext**)
// I get an error on this line under maybeNext.
// Too many arguments for method apply(A)
}
I keep getting an error when trying to initialize the list as I had done earlier and being a beginner to Scala I can't seem to understand why. I have tried the argument with and without backticks and that did not work either. Wondering if it would be possible for someone to help me figure problem out and also I'd like to know if its possible to pattern match a given integer argument "globally" within a function. Thanks!