How to efficiently remove var in Scala - scala

I am trying to solve problem https://www.geeksforgeeks.org/connect-n-ropes-minimum-cost/
Solution
def minCost(arr: Array[Int]):Int = {
val minHeap = scala.collection.mutable.PriorityQueue.empty[Int].reverse
arr.foreach{ ele =>
minHeap += ele
}
var sum =0
while(minHeap.size >1){
val first = minHeap.dequeue()
val second = minHeap.dequeue()
val length = second + first//3+3 =6+9
sum = sum + (first +second)//3+6+9
minHeap.enqueue(length)
}
sum
}
I want to get rid of while loop and var. Can anyone suggest a better solution?
tried below
val res =minHeap.foldLeft(0){
(x,y)=>
val sum =x+y
minHeap.enqueue(sum)
sum
}
println(res)
res

If you only want to remove the var and while but still use a mutable PriorityQueue (which being honest is a good compromise and probably the best to do in real code) you can just use a tail-recursive method.
type Ropes = List[Int]
def connectRopes(ropes: Ropes): Int = {
val queue = PriorityQueue.from(ropes).reverse
#annotation.tailrec
def loop(remaining: Int, acc: Int): Int = {
if (remaining == 0) acc
else if (remaining == 1) acc
else {
val rope1 = queue.dequeue()
val rope2 = queue.dequeue()
val newRope = rope1 + rope2
queue.addOne(newRope)
loop(remaining - 1, acc + newRope)
}
}
loop(remaining = queue.size, acc = 0)
}
But, if you want to write a fully immutable solution just to get used to work with immutable data structures you can do something like this:
def connectRopesFullImmutable(ropes: Ropes): Int = {
#annotation.tailrec
def loop(remaining: Ropes, acc: Int): Int =
remaining match {
case Nil =>
acc
case _ :: Nil =>
acc
case rope1 :: rope2 :: Nil =>
rope1 + rope2 + acc
case rope1 :: rope2 :: tail =>
#annotation.tailrec
def findTwoMin(remaining: Ropes, min1: Int, min2: Int, acc: Ropes): (Int, Int, Ropes) =
remaining match {
case rope :: tail =>
if (rope < min1) findTwoMin(remaining = tail, min1 = rope, min2 = min1, min2:: acc)
else if (rope < min2) findTwoMin(remaining = tail, min1, min2 = rope, min2 :: acc)
else findTwoMin(remaining = tail, min1, min2, rope :: acc)
case Nil =>
(min1, min2, acc)
}
val (min1, min2, ropes) =
if (rope1 < rope2) findTwoMin(remaining = tail, min1 = rope1, min2 = rope2, acc = List.empty)
else findTwoMin(remaining = tail, min1 = rope2, min2 = rope1, acc = List.empty)
val newRope = min1 + min2
loop(remaining = newRope :: ropes, acc + newRope)
}
loop(remaining = ropes, acc = 0)
}
Answering the comment the space complexity of the problem is (AFAIK) O(1), since the algorithm is a tail-recursive function we are not consuming stack and we only manipulate the same list so we are also not consuming heap.
The time complexity is O(N^2) because we have an inner loop inside the outer loop, this means this algorithm is very inefficient.
We may try to optimize it a little by keeping the list of remaining ropes always sorted; as shown below. Which should give use O(N log(N)), but still requires a lot of boilerplate and inefficiency just for not using a mutable priority queue.
def connectRopesFullImmutableOptimized(ropes: Ropes): Int = {
#annotation.tailrec
def loop(remaining: Ropes, acc: Int): Int =
remaining match {
case rope1 :: rope2 :: tail =>
val newRope = rope1 + rope2
#annotation.tailrec
def insertSorted(remaining: Ropes, acc: Ropes): Ropes =
remaining match {
case rope :: ropes =>
if (newRope > rope) insertSorted(remaining = ropes, rope :: acc)
else acc reverse_::: (newRope :: rope :: ropes)
case Nil =>
(newRope :: acc).reverse
}
loop(remaining = insertSorted(remaining = tail, acc = List.empty), acc + newRope)
case _ =>
acc
}
loop(remaining = ropes.sorted, acc = 0)
}
You can see the code running in Scastie.

I'd go with unfold(). (Scala 2.13.x)
import scala.collection.mutable.PriorityQueue
def minCost(arr: Array[Int]): Int =
List.unfold(PriorityQueue(arr:_*).reverse){ pq =>
Option.when(pq.size > 1) {
val link = pq.dequeue() + pq.dequeue()
pq.enqueue(link)
(link, pq)
}
}.sum

Pretty similar #Luis solution, if you are fine with mutability a tail recursion with an accumulator would be sufficient to get rid of vars and loops.
object ConnectRopes extends App {
import scala.annotation.tailrec
import scala.collection.mutable
val arr = List(4, 3, 2, 6)
val minHeap = mutable.PriorityQueue.from(arr)(Ordering[Int].reverse)
#tailrec
def minCost(acc: Int = 0): Int =
if (minHeap.size > 1) {
val connect = minHeap.dequeue + minHeap.dequeue
minHeap.enqueue(connect)
minCost(acc + connect)
} else acc
println(minCost())
}
However I don't think you can have a immutable solution with comparable time complexity just with lists. For an immutable priority queue you will need a Finger Tree like this one from ScalaZ.

Related

Splitting a list of strings into several lists at every predicate scala

Is there a way for splitting a list of strings like following:
List("lorem", "ipsum" ,"X", "sit", "amet", "consectetur")
At every predicate like x => x.equals("X") into several lists that the result would be:
List(List("lorem", "ipsum"), List("sit", "amet", "consectetur"))
That all in a simple functional way?
The unfold() (Scala 2.13.x) way.
val lst =
List("X","lorem","ipsum","X","sit","amet","X","consectetur","X")
List.unfold(lst){st =>
Option.when(st.nonEmpty){
val (nxt, rst) = st.span(_ != "X")
(nxt, rst.drop(1))
}
}
//res0: List[List[String]] = List(List()
// , List(lorem, ipsum)
// , List(sit, amet)
// , List(consectetur))
You can use a tail-recursive function to easily keep track of each chunk like this:
def splitEvery[A](data: List[A])(p: A => Boolean): List[List[A]] = {
#annotation.tailrec
def loop(remaining: List[A], currentChunk: List[A], acc: List[List[A]]): List[List[A]] =
remaining match {
case a :: tail =>
if (p(a))
loop(
remaining = tail,
currentChunk = List.empty,
currentChunk.reverse :: acc
)
else
loop(
remaining = tail,
a :: currentChunk,
acc
)
case Nil =>
(currentChunk.reverse :: acc).reverse
}
loop(
remaining = data,
currentChunk = List.empty,
acc = List.empty
)
}
Which can be used like this:
val data = List("lorem", "ipsum" ,"X", "sit", "amet", "consectetur")
val result = splitEvery(data)(_ == "X")
// result: List[List[String]] = List(List(lorem, ipsum), List(sit, amet, consectetur)
)
You can see the code running here.

Rewriting imperative for loop to declarative style in Scala

How do I rewrite the following loop (pattern) into Scala, either using built-in higher order functions or tail recursion?
This the example of an iteration pattern where you do a computation (comparison, for example) of two list elements, but only if the second one comes after first one in the original input. Note that the +1 step is used here, but in general, it could be +n.
public List<U> mapNext(List<T> list) {
List<U> results = new ArrayList();
for (i = 0; i < list.size - 1; i++) {
for (j = i + 1; j < list.size; j++) {
results.add(doSomething(list[i], list[j]))
}
}
return results;
}
So far, I've come up with this in Scala:
def mapNext[T, U](list: List[T])(f: (T, T) => U): List[U] = {
#scala.annotation.tailrec
def loop(ix: List[T], jx: List[T], res: List[U]): List[U] = (ix, jx) match {
case (_ :: _ :: is, Nil) => loop(ix, ix.tail, res)
case (i :: _ :: is, j :: Nil) => loop(ix.tail, Nil, f(i, j) :: res)
case (i :: _ :: is, j :: js) => loop(ix, js, f(i, j) :: res)
case _ => res
}
loop(list, Nil, Nil).reverse
}
Edit:
To all contributors, I only wish I could accept every answer as solution :)
Here's my stab. I think it's pretty readable. The intuition is: for each head of the list, apply the function to the head and every other member of the tail. Then recurse on the tail of the list.
def mapNext[U, T](list: List[U], fun: (U, U) => T): List[T] = list match {
case Nil => Nil
case (first :: Nil) => Nil
case (first :: rest) => rest.map(fun(first, _: U)) ++ mapNext(rest, fun)
}
Here's a sample run
scala> mapNext(List(1, 2, 3, 4), (x: Int, y: Int) => x + y)
res6: List[Int] = List(3, 4, 5, 5, 6, 7)
This one isn't explicitly tail recursive but an accumulator could be easily added to make it.
Recursion is certainly an option, but the standard library offers some alternatives that will achieve the same iteration pattern.
Here's a very simple setup for demonstration purposes.
val lst = List("a","b","c","d")
def doSomething(a:String, b:String) = a+b
And here's one way to get at what we're after.
val resA = lst.tails.toList.init.flatMap(tl=>tl.tail.map(doSomething(tl.head,_)))
// resA: List[String] = List(ab, ac, ad, bc, bd, cd)
This works but the fact that there's a map() within a flatMap() suggests that a for comprehension might be used to pretty it up.
val resB = for {
tl <- lst.tails
if tl.nonEmpty
h = tl.head
x <- tl.tail
} yield doSomething(h, x) // resB: Iterator[String] = non-empty iterator
resB.toList // List(ab, ac, ad, bc, bd, cd)
In both cases the toList cast is used to get us back to the original collection type, which might not actually be necessary depending on what further processing of the collection is required.
Comeback Attempt:
After deleting my first attempt to give an answer I put some more thought into it and came up with another, at least shorter solution.
def mapNext[T, U](list: List[T])(f: (T, T) => U): List[U] = {
#tailrec
def loop(in: List[T], out: List[U]): List[U] = in match {
case Nil => out
case head :: tail => loop(tail, out ::: tail.map { f(head, _) } )
}
loop(list, Nil)
}
I would also like to recommend the enrich my library pattern for adding the mapNext function to the List api (or with some adjustments to any other collection).
object collection {
object Implicits {
implicit class RichList[A](private val underlying: List[A]) extends AnyVal {
def mapNext[U](f: (A, A) => U): List[U] = {
#tailrec
def loop(in: List[A], out: List[U]): List[U] = in match {
case Nil => out
case head :: tail => loop(tail, out ::: tail.map { f(head, _) } )
}
loop(underlying, Nil)
}
}
}
}
Then you can use the function like:
list.mapNext(doSomething)
Again, there is a downside, as concatenating lists is relatively expensive.
However, variable assignemends inside for comprehensions can be quite inefficient, too (as this improvement task for dotty Scala Wart: Convoluted de-sugaring of for-comprehensions suggests).
UPDATE
Now that I'm into this, I simply cannot let go :(
Concerning 'Note that the +1 step is used here, but in general, it could be +n.'
I extended my proposal with some parameters to cover more situations:
object collection {
object Implicits {
implicit class RichList[A](private val underlying: List[A]) extends AnyVal {
def mapNext[U](f: (A, A) => U): List[U] = {
#tailrec
def loop(in: List[A], out: List[U]): List[U] = in match {
case Nil => out
case head :: tail => loop(tail, out ::: tail.map { f(head, _) } )
}
loop(underlying, Nil)
}
def mapEvery[U](step: Int)(f: A => U) = {
#tailrec
def loop(in: List[A], out: List[U]): List[U] = {
in match {
case Nil => out.reverse
case head :: tail => loop(tail.drop(step), f(head) :: out)
}
}
loop(underlying, Nil)
}
def mapDrop[U](drop1: Int, drop2: Int, step: Int)(f: (A, A) => U): List[U] = {
#tailrec
def loop(in: List[A], out: List[U]): List[U] = in match {
case Nil => out
case head :: tail =>
loop(tail.drop(drop1), out ::: tail.drop(drop2).mapEvery(step) { f(head, _) } )
}
loop(underlying, Nil)
}
}
}
}
list // [a, b, c, d, ...]
.indices // [0, 1, 2, 3, ...]
.flatMap { i =>
elem = list(i) // Don't redo access every iteration of the below map.
list.drop(i + 1) // Take only the inputs that come after the one we're working on
.map(doSomething(elem, _))
}
// Or with a monad-comprehension
for {
index <- list.indices
thisElem = list(index)
thatElem <- list.drop(index + 1)
} yield doSomething(thisElem, thatElem)
You start, not with the list, but with its indices. Then, you use flatMap, because each index goes to a list of elements. Use drop to take only the elements after the element we're working on, and map that list to actually run the computation. Note that this has terrible time complexity, because most operations here, indices/length, flatMap, map, are O(n) in the list size, and drop and apply are O(n) in the argument.
You can get better performance if you a) stop using a linked list (List is good for LIFO, sequential access, but Vector is better in the general case), and b) make this a tiny bit uglier
val len = vector.length
(0 until len)
.flatMap { thisIdx =>
val thisElem = vector(thisIdx)
((thisIdx + 1) until len)
.map { thatIdx =>
doSomething(thisElem, vector(thatIdx))
}
}
// Or
val len = vector.length
for {
thisIdx <- 0 until len
thisElem = vector(thisIdx)
thatIdx <- (thisIdx + 1) until len
thatElem = vector(thatIdx)
} yield doSomething(thisElem, thatElem)
If you really need to, you can generalize either version of this code to all IndexedSeqs, by using some implicit CanBuildFrom parameters, but I won't cover that.

how to check whether given List[Int] is sorted in scala?

I would like to know whether is there any isSorted() function exist or not in scala.
Question: check whether List[Int] is sorted or not, If not remove smallest number and do again till List[Int] become sorted?
I want only 1 or 2 line program.
You can compare each pair in the input sequence for lists containing more than 1 item:
def isSorted[T](s: Seq[T])(implicit ord: Ordering[T]): Boolean = s match {
case Seq() => true
case Seq(_) => true
case _ => s.sliding(2).forall { case Seq(x, y) => ord.lteq(x, y) }
}
It's not the best solution but you can use sorted method on list and then compare it with original one;
def sorted(l: List[Int]): Boolean = l == l.sorted
With some lazyness:
def isSorted(l:List[Int]):Boolean = {
val list = l.view
!list.zip(list.tail).exists {case (x,y) => x>y}
}
Performing a sort just to check if the list is already sorted is a bit of an overkill. The optimal solution here seems to be the most obvious one, which is just describing the problem in human language and transferring it into code:
def isSorted[T](list: List[T])(implicit ord: Ordering[T]): Boolean = list match {
case Nil => true // an empty list is sorted
case x :: Nil => true // a single-element list is sorted
case x :: xs => ord.lteq(x, xs.head) && isSorted(xs) // if the first two elements are ordered and the rest are sorted, the full list is sorted too
}
If you want it shorter, you could trade the 2nd case for a bit of readability:
def isSorted[T](list: List[T])(implicit ord: Ordering[T]): Boolean = list match {
case Nil => true
case x :: xs => xs.headOption.fold(true)(ord.lteq(x, _)) && isSorted(xs)
}
If you want a one-liner, that would be not readable at all:
def isSorted[T](list: List[T])(implicit ord: Ordering[T]): Boolean = list.headOption.fold(true)(a => list.tail.headOption.fold(true)(ord.lteq(a, _) && isSorted(list.tail.tail)))
def isSorted(xs: List[Int]): Boolean = (xs.tail zip xs).forall(pair => pair._1 - pair._2 > 0)
Using `zip`
Lets do it without actually sorting the list.
Drop the head element in the intermediate list and then compare in pairs with original list. This way, ith element compares with i+1th element of the original list.
scala> val originalList = List(10, 20, 30, 40)
val originalList: List[Int] = List(10, 20, 30, 40)
scala> val intermediate = originalList.drop(1)
val intermediate: List[Int] = List(20, 30, 40)
scala> originalList.zip(intermediate)
val res5: List[(Int, Int)] = List((10,20), (20,30), (30,40))
scala> originalList.zip(intermediate).forall { case (orig, in) => orig <= in }
val res17: Boolean = true
A inefficient but easy to understand answer:
def specialSort(a: List[Int]): List[Int] =
if (a == a.sorted) a
else specialSort(a.filterNot(_ == a.min))
l == l.sorted didn't work for me, managed to do it with l sameElements l.sorted
Here your one-line homework solution
def removeMinWhileNotSorted[A: Ordering](xs: List[A]): List[A] = if (xs == xs.sorted) xs else xs.splitAt(xs.indexOf(xs.min)) match {case (prefix, m :: postfix) => removeMinWhileNotSorted(prefix ++ postfix)}
It does not exists. But it is easy to do: create a list with the joined version of the list and the same list sorted as you want and verify both elements of the joined list are the same.
Something like this:
import org.junit.Assert._
val sortedList = List(1, 3, 5, 7)
val unsortedList = List(10, 1, 8, 3, 5, 5, 2, 9)
// detailed test. It passes.
sortedList
.zip(sortedList.sortWith((a,b) => a.compareTo(b) < 0)) // this is the required sorting criteria.
.foreach(x => assertEquals("collection is not sorted", x._1, x._2))
// easier to read but similar test. It fails.
unsortedList
.zip(unsortedList.sorted) // this is the required sorting criteria.
.foreach(x => assertEquals("collection is not sorted", x._1, x._2))
a function could be:
def isSorted(list: List[Int]): Boolean = !list.zip(list.sortWith((a, b) => a.compareTo(b) < 0)).exists(p => !p._1.equals(p._2))
def isSorted[T <% Ordered[T]](list: List[T]): Boolean =
list.sliding(2).forall(p => (p.size==1) || p(0) < p(1))
I assumed that if two neighbor elements are equal it is legal too.
def isSorted[T <% Ordered[T]](l: List[T]):Boolean ={
val a = l.toArray
(1 until a.length).forall(i => a(i-1) <= a(i))
}
Another possibility (not necessarily any better than some of the other suggestions)
def isSorted[T <% Ordered[T]](a: List[T]): Boolean =
if (a == Nil) true // an empty list is sorted
else a.foldLeft((true, a.head))(
(prev, v1) => {
val (p, v0) = prev
(p && v0 <= v1, v1)
})._1
Results for a few test cases:
isSorted(Nil) -> true
isSorted(1 :: Nil) -> true
isSorted(2 :: 3 :: Nil) -> true
isSorted(1 :: 2 :: 5 :: 8 :: Nil) -> true
isSorted(1 :: 1 :: 2 :: 2 :: Nil) -> true
isSorted(3 :: 2 :: Nil) -> false
isSorted(1 :: 2 :: 3 :: 1 :: Nil) -> false
You can use tail recursion to less create objects and to avoid stack overflow for long lists. This version is lazy, function return value instantly after a first unordered pair.
#scala.annotation.tailrec
def isSorted[T : Ordering](values: List[T]): Boolean = {
import scala.math.Ordering.Implicits._
values match {
case fst :: snd :: _ if fst <= snd => isSorted(values.tail)
case _ :: _ :: _ => false
case _ => true
}
}
This works.
def check(list: List[Int]) = {
#tailrec
def isSorted(list: List[Int], no: Int, acc: Boolean): Boolean = {
if (list.tail == Nil) acc
else if (list.head > no) {
isSorted(list.tail, list.head, acc = true)
}
else isSorted(list.tail, list.head, acc=false)
}
isSorted(list, Integer.MIN_VALUE, acc = false)
}

Group List elements with a distance less than x

I'm trying to figure out a way to group all the objects in a list depending on an x distance between the elements.
For instance, if distance is 1 then
List(2,3,1,6,10,7,11,12,14)
would give
List(List(1,2,3), List(6,7), List(10,11,12), List(14))
I can only come up with tricky approaches and loops but I guess there must be a cleaner solution.
You may try to sort your list and then use a foldLeft on it. Basically something like that
def sort = {
val l = List(2,3,1,6,10,7,11,12,14)
val dist = 1
l.sorted.foldLeft(List(List.empty[Int]))((list, n) => {
val last = list.head
last match {
case h::q if Math.abs(last.head-n) > dist=> List(n) :: list
case _ => (n :: last ) :: list.tail
}
}
)
}
The result seems to be okay but reversed. Call "reverse" if needed, when needed, on the lists. the code becomes
val l = List(2,3,1,6,10,7,11,12,14)
val dist = 1
val res = l.sorted.foldLeft(List(List.empty[Int]))((list, n) => {
val last = list.head
last match {
case h::q if Math.abs(last.head-n) > dist=> List(n) :: (last.reverse :: list.tail)
case _ => (n :: last ) :: list.tail
}
}
).reverse
The cleanest answer would rely upon a method that probably should be called groupedWhile which would split exactly where a condition was true. If you had this method, then it would just be
def byDist(xs: List[Int], d: Int) = groupedWhile(xs.sorted)((l,r) => r - l <= d)
But we don't have groupedWhile.
So let's make one:
def groupedWhile[A](xs: List[A])(p: (A,A) => Boolean): List[List[A]] = {
val yss = List.newBuilder[List[A]]
val ys = List.newBuilder[A]
(xs.take(1) ::: xs, xs).zipped.foreach{ (l,r) =>
if (!p(l,r)) {
yss += ys.result
ys.clear
}
ys += r
}
ys.result match {
case Nil =>
case zs => yss += zs
}
yss.result.dropWhile(_.isEmpty)
}
Now that you have the generic capability, you can get the specific one easily.

passing empty List argument is invoking IndexOutOfBoundsException

I am trying inversion counting in Scala with merge sort and not able to make progress because one of the method is throwing IndexOutOfBoundsException for passing empty List as a parameter.
def sortAndCountInv(il: List[Int]): Int = {
def mergeAndCountInv(ll: List[Int], rl: List[Int]): (List[Int], Int) = {
println("mergeAndCountInv : ")
if (ll.isEmpty && !rl.isEmpty) (rl, 0)
if (rl.isEmpty && !ll.isEmpty) (ll, 0)
if (ll.isEmpty && rl.isEmpty) (List(), 0)
if (ll(0) <= rl(0)) {
val x = mergeAndCountInv(ll.tail, rl)//*passing empty list, ll.tail invoking IndexOutOfBoundsException*//
(ll(0) :: x._1, x._2)
} else {
val y = mergeAndCountInv(ll, rl.tail)
(rl(0) :: y._1, 1 + y._2)
}
}
def sortAndCountInv(l: List[Int], n: Int): (List[Int], Int) = {
if (n <= 1) (l, 0)
else {
val two_lists = l.splitAt(n / 2)
val x = sortAndCountInv(two_lists._1, n / 2)
val y = sortAndCountInv(two_lists._2, n / 2)
val z = mergeAndCountInv(x._1, y._1)
(z._1, x._2 + y._2 + z._2)
}
}
val r = sortAndCountInv(il, il.length)
println(r._1.take(100))
r._2
}
This sort of thing is often more clearly expressed using pattern matching:
def mergeAndCountInv(ll: List[Int], rl: List[Int]): (List[Int], Int) =
(ll, rl) match {
case (Nil, Nil) => (Nil, 0)
case (Nil, _) => (rl, 0)
case (_, Nil) => (ll, 0)
case (ll0 :: moreL, rl0 :: moreR) =>
if (ll0 <= rl0) {
val x = mergeAndCountInv(moreL, rl)
(ll0 :: x._1, x._2)
}
else {
val y = mergeAndCountInv(ll, moreR)
(rl0 :: y._1, 1 + y._2)
}
}
I would suggest using else in mergeAndCountInv when you check if left or right or both of lists are empty. Because instead of return you ignore a tuple with your calculations.