Generate a list of Tuple2 objects meeting some conditions

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


Generate a list of Tuple2 objects meeting some conditions



I want to generate a list of Tuple2 objects. Each tuple (a,b) in the list should meet the following 4 conditions:


list


Tuple2 objects


(a,b)


a


b


b>a


a/b


1/30


a


b


Number N


N


BigInt



How to write a scala function to generate the List of Tuples meeting the above requirements?( Even better if the a and b lies in a given interval (N1,N2) where N2>N1 instead of above 4th condition)


scala function


the List of Tuples


a


b


interval (N1,N2)


N2>N1



This is my attempt..may be it is fine for Ints and Longs..But for BigInt there is sqrt problem I am facing..Please correct if I am wrong in my approach in coding as below:


scala> def genTups(N:Long) ={
| val x = for(s<- 1L to Math.sqrt(N).toLong) yield s*s;
| val y = x.combinations(2).map{ case Vector(a,b) => (a,b)}.toList
| y.filter(t=> (t._1*30/t._2)>=1)
| }
genTups: (N: Long)List[(Long, Long)]

scala> genTups(30)
res32: List[(Long, Long)] = List((1,4), (1,9), (1,16), (1,25), (4,9), (4,16), (4,25), (9,16), (9,25), (16,25))



Improved this using BigInt square-root algorithm as below:


def genTups(N1:BigInt,N2:BigInt) ={
def sqt(n:BigInt):BigInt = {
var a = BigInt(1)
var b = (n>>5)+BigInt(8)
while((b-a) >= 0) {
var mid:BigInt = (a+b)>>1
if(mid*mid-n> 0) b = mid-1
else a = mid+1
}; a-1 }
val x = for(s<- sqt(N1) to sqt(N2)) yield s*s;
val y = x.combinations(2).map{ case Vector(a,b) => (a,b)}.toList
y.filter(t=> (t._1*30/t._2)>=1)
}



I invite any improvements in my algo or any limitations/lapses in this algorithm.





What have you tried so far? What problems did you have? Show your attempt and you will get advice on how to improve it, but don't just ask people to complete your assignments for you.
– Tim
7 hours ago





You don't need the condition on the case clause because combinations keeps the values in order and a is always <b. If it wasn't, the map would fail with an exception.
– Tim
44 mins ago


case


combinations


a


<b


map





Yes..Just now I too realised that. can it improve performance a bit if I remove it?
– RAGHHURAAMM
32 mins ago







Yes, but I just added a faster implementation you might want to look at
– Tim
2 mins ago




2 Answers
2



You can avoid sqrt in you algorithm by changing the way you calculate x to this:


sqrt


x


val x = (BigInt(1) to N).map(x => x*x).takeWhile(_ <= N)



The final function is then:


def genTups(N: BigInt) = {
val x = (BigInt(1) to N).map(x => x*x).takeWhile(_ <= N)
val y = x.combinations(2).map { case Vector(a, b) if (a < b) => (a, b) }.toList
y.filter(t => (t._1 * 30 / t._2) >= 1)
}



You can also re-write this as a single chain of operations like this:


def genTups(N: BigInt) =
(BigInt(1) to N)
.map(x => x * x)
.takeWhile(_ <= N)
.combinations(2)
.map { case Vector(a, b) if a < b => (a, b) }
.filter(t => (t._1 * 30 / t._2) >= 1)
.toList



In a quest for performance, I came up with this recursive version that appears to be significantly faster


def genTups(N1: BigInt, N2: BigInt) = {
def sqt(n: BigInt): BigInt = {
var a = BigInt(1)
var b = (n >> 5) + BigInt(8)
while ((b - a) >= 0) {
var mid: BigInt = (a + b) >> 1
if (mid * mid - n > 0) {
b = mid - 1
} else {
a = mid + 1
}
}
a - 1
}

@tailrec
def loop(a: BigInt, rem: List[BigInt], res: List[(BigInt, BigInt)]): List[(BigInt, BigInt)] =
rem match {
case Nil => res
case head :: tail =>
val a30 = a * 30
val thisRes = rem.takeWhile(_ < a30).map(b => (a, b))

loop(head, tail, thisRes.reverse ::: res)
}

val squares = (sqt(N1) to sqt(N2)).map(s => s * s).toList

loop(squares.head, squares.tail, Nil).reverse
}



Each recursion of the loop adds all the matching pairs for a given value of a. The result is built in reverse because adding to the front of a long list is much faster than adding to the tail.


a





That's small but very useful tip..Avoided exploring me for proper sqrt function for BigInt. Thanks Tim.
– RAGHHURAAMM
3 hours ago





After examining your suggestion, I got another issue regarding performance of both approaches..In my approach I am just computing squares from 1 to sqrt(N) only, But in this approach we are computing right from 1 to N and filtering the computed squares using takeWhile(), where N may be very large than sqrt(N). Do you have anything to clarify on this?
– RAGHHURAAMM
1 hour ago


takeWhile()





@RAGHHURAAMM this could be performance killer for larger number as the combinations method would be compute intensive
– Chaitanya Waikar
1 hour ago





You can improve things by putting .view before .map and changing Vector to Seq, but if you are going for better performance you probably need a better algorithm.
– Tim
1 hour ago


.view


.map


Vector


Seq





Is there any better way than using combinations method here?
– RAGHHURAAMM
1 hour ago



Firstly create a function to check if number if perfect square or not.


def squareRootOfPerfectSquare(a: Int): Option[Int] = {
val sqrt = math.sqrt(a)
if (sqrt % 1 == 0)
Some(sqrt.toInt)
else
None
}



Then, create another func that will calculate this list of tuples according to the conditions mentioned above.


def generateTuples(n1:Int,n2:Int)={
for{
b <- 1 to n2;
a <- 1 to n1 if(b>a && squareRootOfPerfectSquare(b).isDefined && squareRootOfPerfectSquare(a).isDefined)
} yield ( (a,b) )
}



Then on calling the function with parameters generateTuples(5,10)
you will get an output as


generateTuples(5,10)


res0: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,4), (1,9), (4,9))



Hope that helps !!!





I think you have missed out the code for generateTuple and put two copies of squareRootOfPerfectSquare instead...
– Tim
1 hour ago


generateTuple


squareRootOfPerfectSquare





@Tim Thanks for pointing out. I am wondering why my answer was not accepted all this time. Anyways thanks !!!
– Chaitanya Waikar
1 hour ago





Also, the question asks for a solution for BigInt so you can't use sqrt :(
– Tim
1 hour ago


BigInt


sqrt






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Arduino Mega cannot recieve any sketches, stk500_recv() programmer is not responding

Visual Studio Code: How to configure includePath for better IntelliSense results

Future solutions