Scala - Remove while loop in quick sort - scala

def QuickSort(arr:Array[Int],first:Int,last:Int): List[Int] = {
var pivot:Int = 0
var temp:Int = 0
if (first < last) {
pivot = first
var i:Int = first
var j:Int = last;
while(i<j){
while(arr(i) <= arr(pivot) && i < last)
i=i+1
while(arr(j) > arr(pivot))
j=j+1
if(i<j)
{
temp = arr(i)
arr(i) = arr(j)
arr(j) = temp
}
}
temp = arr(pivot)
arr(pivot) = arr(j)
arr(j) = temp
QuickSort(arr, first, j-1)
QuickSort(arr, j+1, last)
}
arr.toList
}
Hello I m new to scala and trying to implement quick sort. Program is working correctly but I want to remove the while loop since I read that while and do while are not recommended in scala because they do not return any value.
Is there any way to remove while loop in above code.

The classic quicksort algorithm, as you've coded here, requires a mutable collection (like Array) and the swapping of element values, which requires mutable variables (i.e. var). These things are discouraged in functional programming and aren't held in high esteem in the Scala community.
Here's a similar approach that is a little more in keeping to the spirit of the FP ethic.
// pseudo-quicksort -- from Array[Int] to List[Int]
def pqs(arr:Array[Int]): List[Int] = arr match {
case Array() => List()
case Array(x) => List(x)
case Array(x,y) => if (x < y) List(x,y) else List(y,x)
case _ => val (below, above) = arr.partition(_ < arr(0))
pqs(below) ++ List(arr(0)) ++ pqs(above.tail)
}
Better yet is to use one of the sort methods (sortBy, sortWith, sorted) as offered in the standard library.

Not so elegant, but without while:
def QuickSort(l: List[Int]) : List[Int] = {
if( l.length == 0) return Nil
if( l.length == 1 ) return arr
val pivot = arr(arr.length / 2)
val lesserThanPivot = l.filter( _ < pivot)
val equalToPivot = l.filter( _ == pivot)
val biggerThanPivot = l.filter( _ > pivot)
QuickSort( lesserThanPivot ) ++ equalToPivot.tail ++ List(pivot) ++ QuickSort(biggerThanPivot)
}

Related

Move zeros to the end of an Array

Im trying to solve below problem in scala
Input:[1,0,44,55,0,43,78,99]
output:[1,44,55,43,78,99,0,0]
here is what i have tried
def moveZeros(nums:Array[Int]): Array[Int] ={
for(i<-0 until nums.length ; j<-0 until nums.length){
if(nums(j)!=0)
{
var temp:Int = nums(i)
nums(i)=nums(j)
nums(j)=temp
}
}
nums
}
output :[0,0,1,44,55,78,99,43]
not expected output
Im looking for o(n) time complexity and O(1) space complexity solution
This is a leetcode problem
https://leetcode.com/problems/move-zeroes/
You can try something like that:
nums.zipWithIndex
.sortBy(t => if (t._1 == 0) Int.MaxValue else t._2)
.map(_._1)
zipWithIndex will map your collection into sequence of tuples of element value and it's index (i.e. [(1, 0), (0, 21), (44, 2)] for start of your example array)
sortBy will perform the ordering by either index of element or Int.MaxValue
map will return map to the original element.
i have rewritten my code with while loop it seems to work, lemme know if there is more elegant solution which satisfies linear time complexity and constant space complexity
def moveZeros(nums: Array[Int]): Array[Int] = {
var i = 0
var j = 0
while ( {
i < nums.length && j < nums.length
}) {
if (nums(j) != 0) {
val tmp = nums(i)
nums(i)=nums(j)
nums(j) = tmp
i+=1
}
j += 1
}
nums
}
This is a pure FP solution with O(n) time complexity and O(1) space complexity.
Unlike any of the other solutions so far, it can work for very large input that doesn't fit in memory:
object MoveZeros extends App {
def moveZerosToEnd(input: Iterator[Int]): Iterator[Int] = {
val endOfInputSignal = None
val iteratorWithEndSignal: Iterator[Option[Int]] =
input.map(Some(_)) ++ Iterator.single(endOfInputSignal)
iteratorWithEndSignal.scanLeft((0, Iterator.empty[Int])) {
case ((zerosCounter, _), value) => value match {
case Some(value) =>
if (value == 0)
// Count zero and drop it
(zerosCounter + 1, Iterator.empty)
else
(zerosCounter, Iterator.single(value))
case None =>
// Add counted zeros to the end
(zerosCounter, Iterator.fill(zerosCounter)(0))
}
}.flatMap(_._2)
}
val input = List(1,0,44,55,0,43,78,99)
val expected = List(1,44,55,43,78,99,0,0)
val res = moveZerosToEnd(input.iterator)
.toList // To list only for easy testing
assert(res == expected)
println(res)
}
Functional and immutable solution, also very simple to understand:
def moveZerosToEnd(input: Seq[Int]): Seq[Int] = {
val ZERO = 0
val zeroCount = input.count(_==ZERO)
val removeZeros = input.filter(_!=ZERO)
val zeroSuffix = Seq.fill(zeroCount)(ZERO)
removeZeros ++ zeroSuffix
}
Time complexity: O(n): Fixed number of iterations over the sequence.
Space complexity: O(n): removeZeros, zeroSuffix and the output line may consume up to n space, so complexity is O(n).
You can find all the immutable, functional, "true Scala" way of doing it in the above answers. But, considering the O(N) time-complexity and O(1) space complexity nothing beats a mutable, efficient, in-place algorithm!
Here is the implementation with Scala's array using foldLeft:
val arr = Array(1, 0, 44, 55, 0, 43, 78, 99)
val lastNonZero = arr.foldLeft(0) {
(zeros, elem) => if (elem != 0) { arr(zeros) = elem; zeros+1 } else zeros
}
(lastNonZero until arr.length).foreach{ i => arr(i) = 0 }
No extra space due to collection creation (not even .toList/.toArray) and no sorting.

SCALA: Generating a list of Tuple2 objects meeting some criteria

I want to generate a list of Tuple2 objects. Each tuple (a,b) in the list should meeting the conditions:a and b both are perfect squares,(b/30)<a<b
and a>N and b>N ( N can even be a BigInt)
I am trying to write a scala function to generate the List of Tuples meeting the above requirements?
This is my attempt..it works fine for Ints and Longs..But for BigInt there is sqrt problem I am facing..Here is 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 appreciate any help to improve in my algorithm .
You can avoid sqrt in you algorithm by changing the way you calculate x to this:
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.
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
res0: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,4), (1,9), (4,9))
Hope that helps !!!

Combine multiple sequential entries in Scala/Spark

I have an array of numbers separated by comma as shown:
a:{108,109,110,112,114,115,116,118}
I need the output something like this:
a:{108-110, 112, 114-116, 118}
I am trying to group the continuous numbers with "-" in between.
For example, 108,109,110 are continuous numbers, so I get 108-110. 112 is separate entry; 114,115,116 again represents a sequence, so I get 114-116. 118 is separate and treated as such.
I am doing this in Spark. I wrote the following code:
import scala.collection.mutable.ArrayBuffer
def Sample(x:String):ArrayBuffer[String]={
val x1 = x.split(",")
var a:Int = 0
var present=""
var next:Int = 0
var yrTemp = ""
var yrAr= ArrayBuffer[String]()
var che:Int = 0
var storeV = ""
var p:Int = 0
var q:Int = 0
var count:Int = 1
while(a < x1.length)
{
yrTemp = x1(a)
if(x1.length == 1)
{
yrAr+=x1(a)
}
else
if(a < x1.length - 1)
{
present = x1(a)
if(che == 0)
{
storeV = present
}
p = x1(a).toInt
q = x1(a+1).toInt
if(p == q)
{
yrTemp = yrTemp
che = 1
}
else
if(p != q)
{
yrTemp = storeV + "-" + present
che = 0
yrAr+=yrTemp
}
}
else
if(a == x1.length-1)
{
present = x1(a)
yrTemp = present
che = 0
yrAr+=yrTemp
}
a = a+1
}
yrAr
}
val SampleUDF = udf(Sample(_:String))
I am getting the output as follows:
a:{108-108, 109-109, 110-110, 112, 114-114, 115-115, 116-116, 118}
I am not able to figure out where I am going wrong. Can you please help me in correcting this. TIA.
Here's another way:
def rangeToString(a: Int, b: Int) = if (a == b) s"$a" else s"$a-$b"
def reduce(xs: Seq[Int], min: Int, max: Int, ranges: Seq[String]): Seq[String] = xs match {
case y +: ys if (y - max <= 1) => reduce(ys, min, y, ranges)
case y +: ys => reduce(ys, y, y, ranges :+ rangeToString(min, max))
case Seq() => ranges :+ rangeToString(min, max)
}
def output(xs: Array[Int]) = reduce(xs, xs.head, xs.head, Vector())//.toArray
Which you can test:
println(output(Array(108,109,110,112,114,115,116,118)))
// Vector(108-110, 112, 114-116, 118)
Basically this is a tail recursive function - i.e. you take your "variables" as the input, then it calls itself with updated "variables" on each loop. So here xs is your array, min and max are integers used to keep track of the lowest and highest numbers so far, and ranges is the output sequence of Strings that gets added to when required.
The first pattern (y being the first element, and ys being the rest of the sequence - because that's how the +: extractor works) is matched if there's at least one element (ys can be an empty list) and it follows on from the previous maximum.
The second is if it doesn't follow on, and needs to reset the minimum and add the completed range to the output.
The third case is where we've got to the end of the input and just output the result, rather than calling the loop again.
Internet karma points to anyone who can work out how to eliminate the duplication of ranges :+ rangeToString(min, max)!
here is a solution :
def combineConsecutive(s: String): Seq[String] = {
val ints: List[Int] = s.split(',').map(_.toInt).toList.reverse
ints
.drop(1)
.foldLeft(List(List(ints.head)))((acc, e) => if ((acc.head.head - e) <= 1)
(e :: acc.head) :: acc.tail
else
List(e) :: acc)
.map(group => if (group.size > 1) group.min + "-" + group.max else group.head.toString)
}
val in = "108,109,110,112,114,115,116,118"
val result = combineConsecutive(in)
println(result) // List(108-110, 112, 114-116, 118)
}
This solution partly uses code from this question: Grouping list items by comparing them with their neighbors

Selection Sort in Scala

I am new to Scala and was trying the Selection Sort algorithm. I managed to do a min sort but when I try to do the max sort I get a sorted array but in decreasing order. My code is:
def maxSort(a:Array[Double]):Unit = {
for(i <- 0 until a.length-1){
var min = i
for(j <- i + 1 until a.length){
if (a(j) < a(min)) min = j
}
val tmp = a(i)
a(i) = a(min)
a(min) = tmp
}
}
I know that I have to append my result at the end of the array, but how do I do that?
This code will sort the array using the maximum in increasing order:
def maxSort(a:Array[Double]):Unit = {
for (i <- (0 until a.length).reverse) {
var max = i
for (j <- (0 until i).reverse) {
if (a(j) > a(max)) max = j
}
val tmp = a(i)
a(i) = a(max)
a(max) = tmp
}
}
The main issue here is iterating through the array in reverse order, more solutions are provided here:
Scala downwards or decreasing for loop?
Please note that Scala is praised for it's functional features and functional approach might be more interesting and "in the style of language". Here are some examples of Selection Sort:
Selection sort in functional Scala
Select Sort in functional style:
def selectionSort(source: List[Int]) = {
def select(source: List[Int], result: List[Int]) : List[Int] = source match {
case h :: t => sort(t, Nil, result, h)
case Nil => result
}
#tailrec
def sort(source: List[Int], r1: List[Int], r2: List[Int], m: Int) : List[Int] = source match {
case h :: t => if( h > m) sort(t, h :: r1, r2, m) else sort(t, m :: r1, r2, h)
case Nil => select(r1, r2 :+ m)
}
select(source, Nil)
}

Scala Breeze adding row and column header to DenseMatrix

Below is an example of code which will generate Correlation Matrix but I need to add column header and row header in front and top of matrix.
For example in the above matrix amber coloured objects are the labels which i need to add to the blue coloured data generated by Correlation matrix whose code i have attached below.
In Scala breeze is there a way to add labels to matrix ? The problem is DenseMatrix is Double and labels are character so i am not able to add any char label to matrix object.
def getCorMatrix(c :String,d :String,n :Int) :breeze.linalg.DenseMatrix[Double] = {
CorMatrixlogger.info("Inside generating Correlation Matrix")
val query = MongoDBObject("RunDate" -> d) ++ ("Country" -> c)
CorMatrixlogger.info("Query Object created for {}", c)
val dbObject = for (d <- price.find(query)) yield(d)
val objectReader = (dbObject map {x => objectRead(x)}).toList
val fetchAssetData = objectReader map {x => x.Symbol} map { x=> assetStats(x,n) } filterNot {x => x.length < n-1}
CorMatrixlogger.info("Asset Data fetched")
val excessReturnMatrix = DenseMatrix((for(i <- fetchAssetData) yield i.excessReturn).map(_.toArray):_*)
CorMatrixlogger.info("Excess Return matrix generated")
val transposeExcessreturnMatrix = excessReturnMatrix.t
val vcvMatrix = breeze.numerics.rint(((excessReturnMatrix * transposeExcessreturnMatrix):/ (n-1).toDouble ) :* 1000000.0) :/ 1000000.0
CorMatrixlogger.info("VcV Matrix Generated")
val transposeStDevVector = DenseMatrix(for (i <- fetchAssetData ) yield i.sigma)
val stDevVector = transposeStDevVector.t
val stDevMatrix = breeze.numerics.rint(( stDevVector * transposeStDevVector) :* 1000000.0) :/ 1000000.0
CorMatrixlogger.info("Correlation Matrix Generated")
lowerTriangular(breeze.numerics.rint((vcvMatrix :/ stDevMatrix) :* 10000.0) :/ 10000.0)
}
Edit
Thanks David. Your solution really worked well for me.
val ma = DenseMatrix((1.0,2.0,3.0), (3.0,4.0,5.0),(6.0,7.0,8.0))
val im = DenseMatrix.tabulate(ma.rows,ma.cols)(ma(_,_).toString)
val head = DenseVector("a","b","c")
val thead = head.t
val withHeader:DenseMatrix[String] = DenseMatrix.tabulate(im.rows+1, im.cols+1) { (i, j) =>
if (i == 0 && j == 0) " "
else if (i == 0) head(j -1)
else if (j == 0 ) thead (i -1)
else im(i-1,j-1)
} //> withHeader : breeze.linalg.DenseMatrix[String] = a b c
//| a 1.0 2.0 3.0
//| b 3.0 4.0 5.0
//| c 6.0 7.0 8.0
There's nothing built in, sadly. You could do something like
val withHeader:DenseMatrix[Any] = DenseMatrix.tabulate(n+1, m+1){ (i, j) =>
if (i == 0 && j == 0) ""
else if (i == 0) colHeaders(j - 1)
else if (j == 0) rowHeaders(i - 1)
else orig(i - 1, j - 1)
}
You lose all typing information that way, of course, but if you just need to toString something, it's probably the quickest way in current Breeze.