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.
Related
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.
I'm trying to figure out how to create an Akka Streams source that generates many Seq[Int].
Basically, given an int n I want to generate all of the Seq[Int] of 1 to n
Here's some code that does this:
def combinations(n: Int): Seq[Seq[Int]] = {
def loop(acc: (Seq[Int], Seq[Seq[Int]]),
remaining: Seq[Int]): Seq[Seq[Int]] = {
remaining match {
case s if s.size == 1 => {
val total: Seq[Seq[Int]] = acc._2
val current: Seq[Int] = acc._1
total :+ (current :+ s.head)
}
case _ => {
for {
x <- remaining
comb <- loop((acc._1 :+ x, acc._2), remaining.filter(_ != x))
} yield comb
}
}
}
loop((Seq(), Seq()), (1 to n))
}
This works fine up to 10... then it blows up because it runs out of memory. Since I just want to process each of them and don't need to keep them all in memory, I thought... Akka Streams. But I'm at a loss for how to turn this into a Source that produces each combination so I can process them. Basically there where it's appending to total I would produce another item onto the stream.
Here is a solution that uses the Johnson-Trotter algorithm for permutations. tcopermutations creates a LazyList that can be evaluated as needed. For more permutations, just pass a different value to printNIterations.
The reason for using the Johnson-Trotter algorithm is that it breaks the recursive structure of the permutation finding algorithm. That's important for being able to evaluate successive instances of the permutation and storing them in some kind of lazy list or stream.
object PermutationsTest {
def main(args: Array[String]) = {
printNIterations(50, tcopermutations(5).iterator)
}
def printNIterations(n: Int, it: Iterator[Seq[Int]]): Unit = {
if (n<=0) ()
else {
if (it.hasNext) {
println(it.next())
printNIterations(n - 1, it)
} else ()
}
}
def naivepermutations(n: Int): Seq[Seq[Int]] = {
def loop(acc: Seq[Int], remaining: Seq[Int]): Seq[Seq[Int]] = {
remaining match {
case s if s.size == 1 => {
val current: Seq[Int] = acc
Seq((current :+ s.head))
}
case _ => {
for {
x <- remaining
comb <- loop(acc :+ x, remaining.filter(_ != x))
} yield comb
}
}
}
loop(Seq(), (1 to n))
}
def tcopermutations(n: Int): LazyList[Seq[Int]] = {
val start = (1 to n).map(Element(_, Left))
def loop(v: Seq[Element]): LazyList[Seq[Element]] = {
johnsonTrotter(v) match {
case Some(s) => v #:: loop(s)
case None => LazyList(v)
}
}
loop(start).map(_.map(_.i))
}
def checkIfMobile(seq: Seq[Element], i: Int): Boolean = {
val e = seq(i)
def getAdjacent(s: Seq[Element], d: Direction, j: Int): Int = {
val adjacentIndex = d match {
case Left => j - 1
case Right => j + 1
}
s(adjacentIndex).i
}
if (e.direction == Left && i == 0) false
else if (e.direction == Right && i == seq.size - 1) false
else if (getAdjacent(seq, e.direction, i) < e.i) true
else false
}
def findLargestMobile(seq: Seq[Element]): Option[Int] = {
val mobiles = (0 until seq.size).filter{j => checkIfMobile(seq, j)}
if (mobiles.isEmpty) None
else {
val folded = mobiles.map(x=>(x,seq(x).i)).foldLeft(None: Option[(Int, Int)]){ case (acc, elem) =>
acc match {
case None => Some(elem)
case Some((i, value)) => if (value > elem._2) Some((i, value)) else Some(elem)
}
}
folded.map(_._1)
}
}
def swapLargestMobile(seq: Seq[Element], index: Int): (Seq[Element], Int) = {
val dir = seq(index).direction
val value = seq(index).i
dir match {
case Right =>
val folded = seq.foldLeft((None, Seq()): (Option[Element], Seq[Element])){(acc, elem) =>
val matched = elem.i == value
val newAccOpt = if (matched) Some(elem) else None
val newAccSeq = acc._1 match {
case Some(swapMe) => acc._2 :+ elem :+ swapMe
case None => if (matched) acc._2 else acc._2 :+ elem
}
(newAccOpt, newAccSeq)
}
(folded._2, index + 1)
case Left =>
val folded = seq.foldRight((None, Seq()): (Option[Element], Seq[Element])){(elem, acc) =>
val matched = elem.i == value
val newAccOpt = if (matched) Some(elem) else None
val newAccSeq = acc._1 match {
case Some(swapMe) => swapMe +: elem +: acc._2
case None => if (matched) acc._2 else elem +: acc._2
}
(newAccOpt, newAccSeq)
}
(folded._2, index - 1)
}
}
def revDirLargerThanMobile(seq: Seq[Element], mobile: Int) = {
def reverse(e: Element) = {
e.direction match {
case Left => Element(e.i, Right)
case Right => Element(e.i, Left)
}
}
seq.map{ elem =>
if (elem.i > seq(mobile).i) reverse(elem)
else elem
}
}
def johnsonTrotter(curr: Seq[Element]): Option[Seq[Element]] = {
findLargestMobile(curr).map { m =>
val (swapped, newMobile) = swapLargestMobile(curr, m)
revDirLargerThanMobile(swapped, newMobile)
}
}
trait Direction
case object Left extends Direction
case object Right extends Direction
case class Element(i: Int, direction: Direction)
}
I am currently trying to write an inversion count algorithm in Scala, utilizing a working merge-sort algorithm.
The merge-sort functions as expected but when I try to add a count as one of the parameters I get back the error:
Error:(14, 29) ';' expected but ',' found.
case (_, Nil) => left, count
^
Here is the program:
object MergeSort {
def mergeSort(inputList: List[Int]): List[Int] = {
if (inputList.length <= 1) inputList
else {
val (left, right) = inputList.splitAt(inputList.size / 2)
merge(mergeSort(left), mergeSort(right), 0)
}
}
def merge(left: List[Int], right: List[Int], count: Int): List[Int] =
(left, right) match {
case (_, Nil) => left, count
case (Nil, _) => right, count
case (leftHead :: leftTail, rightHead :: rightTail) =>
if (leftHead < rightHead){
val (leftList, leftCount) = leftHead :: merge(leftTail, right, count)
return (leftList, leftCount)
}
else {
val (rightList, rightCount) = rightHead :: merge(left, rightTail, count)
val mergeInversions = leftCount + left.length
return (rightList, mergeInversions)
}
}
val inputList: List[Int] = List(10, 3, 5, 1, 7, 6)
val sorted_arr = mergeSort(inputList)
}
#sepp2k pointed out correctly in the comment that if you want to create a tuple, then you need to wrap it around parentheses.
Here's the working solution:
object MergeSort {
def mergeSort(inputList: List[Int]): List[Int] = {
if (inputList.length <= 1) inputList
else {
val (left, right) = inputList.splitAt(inputList.size / 2)
merge(mergeSort(left), mergeSort(right), 0)._1
}
}
def merge(left: List[Int], right: List[Int], count: Int): (List[Int], Int) =
(left, right) match {
case (_, Nil) => (left, count)
case (Nil, _) => (right, count)
case (leftHead :: leftTail, rightHead :: rightTail) =>
if (leftHead < rightHead) {
val left = merge(leftTail, right, count)
val (leftList, leftCount) = (leftHead :: left._1, left._2)
(leftList, leftCount)
} else {
val right = merge(left, rightTail, count)
val (rightList, rightCount) = (rightHead :: right._1, right._2)
val mergeInversions = rightCount + left.length
(rightList, mergeInversions)
}
}
val inputList: List[Int] = List(10, 3, 5, 1, 7, 6, 0)
val sorted_arr = mergeSort(inputList)
}
I'm new in Scala.
For example, I have a List like
val s = List(5, 11, 15, 7)
and I need a lambda function to create a new list of the indexes of the elements that are more than 10. I can not use the language Scala libraries or functions. Only standard Scala opportunities.
How can I calculate the indices of these elements? Thank you!
Try this code:
val lambda = (list: List[Int]) => {
def filterList(l : List[Int], condition : Int, index: Int, acc: List[(Int, Int)]) : List[(Int, Int)] = l match {
case List() => acc
case h::tail =>
if (h > condition) filterList( tail, condition, index + 1, (index, h) :: acc )
else filterList( tail, condition, index + 1, acc )
}
filterList(list, 10, 0, List() )
}
val r = lambda( s )
Well... there are may ways to solve this.
First lets see the more wide-spread "imperative"-like solution with var,
val lambda = (list: List[Int]) => {
var indexList = List.empty[Int]
var i = 0
for (elem <- list) {
if (elem > 10) indexList = i +: indexList
i = i + 1
}
indexList.reverse
}
Now... we can look at a bit more "functional-like" recursive approach,
val lambda = (list: List[Int]) => {
def _inner(list: List[Int], index: Int, indexList: List[Int]) = {
list match {
case Nil => indexList
case elem :: tail => {
if (elem > 10) _inner(tail, index + 1, index +: indexList)
else _inner(tail, index + 1, indexList)
}
}
}
_inner(list, 0, List.empty[Int]).reverse
}
So I have a list of 0's and 1's, I want to find the count of each element and output this to a list. I can think of a recursive way to do it with functions but is there any helper functions which can help to convert this?
I believe groupBy could be useful but it seems to group all the elements into one partition or another, not into the way I want.
I want to have a list of the count of numbers until each transition from 0 to 1 and 1 to 0. ie, if we have 0,0,0, .. ok we counted 3 zeros so remember 3, then we have 1,1,1,1 so we counted 4 1's, so we remember 4, so far we have a list of [3,4...] and so on
tail-rec version of Yann Moisan's solution:
def pack[A](ls: Seq[A], prev: Seq[Int] = Seq.empty): Seq[Int] = {
if (ls.isEmpty) prev
else {
val (packed, next) = ls span {_ == ls.head }
pack(next, prev :+ packed.size)
}
}
def pack[A](ls: List[A]): List[Int] = {
if (ls.isEmpty) List(0)
else {
val (packed, next) = ls span { _ == ls.head }
if (next == Nil) List(packed.size)
else packed.size :: pack(next)
}
}
This might be a little complicated. but I'd go with it.
scala> implicit class ListHelper[A](ls:List[A]) {
def partitionBy(f: (A, A) => Boolean) = if (ls.isEmpty) List.empty[Int]
else (ls zip (ls.head :: ls)).foldLeft(List.empty[Int]){
case (Nil, _) => List(1)
case (x :: xs, (a, b)) => if (a == b) (x + 1) :: xs else 1 :: x :: xs
}.reverse
}
defined class ListHelper
scala> List(0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1).partitionBy(_ == _)
res27: List[Int] = List(3, 4, 2, 2)
This is based on the clojure function partition-by
This is groupBy.
val tuple = list.foldRight((0,0)) { (x, accum) =>
if (x == 0) (accum._1 +1, accum._2) else (accum._1, accum._2 +1)
}
List(tuple._1, tuple._2)
on similar lines here is fliptracker (for non-empty lists):
def fliptracker(list: List[Int]) = {
val initial = (list.head, 0, List.empty[Int])
val result = list.foldLeft(initial) {
(acc, x) =>
if (acc._1 == x) (acc._1, acc._2 + 1, acc._3)
else (x, 1, acc._3 ::: List(acc._2))
}
result._3 ::: List (result._2)
}
fliptracker(List(0,0,0,1,1,1,1,0,0,1,1)) // List(3, 4, 2, 2)
I would do
List(0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1).foldLeft (List.empty[(Any,Int)]) {
(acc,a) => acc match {
case (`a`, occ) :: tail => (a,occ+1) :: tail
case _ => (a,1) :: acc
}}.reverse.map(_._2)
res1: List[Int] = List(3, 4, 2, 2)
Another alternative answer based upon takeWhile. In this 1==black and 0==white
case class IndexCount(index: Int, count: Int, black: Boolean)
#tailrec
def takeWhileSwitch(black: Boolean, index:Int, list: List[Boolean],
result: List[IndexCount]): List[IndexCount] = {
if (list == Nil) return result.reverse
val takenWhile = list.takeWhile(black == _)
val takenLength = takenWhile.length
val resultToBuild = if (takenLength != 0) {
val indexCount = IndexCount(index, takenLength, black)
indexCount :: result
} else result
takeWhileSwitch(!black, index + takenLength, list.drop(takenLength), resultToBuild)
}
val items = takeWhileSwitch(true, 0, rowsWithBlack, List[IndexCount]())
Nobody expects the imperative solution:
def chunk[A](xs: List[A]) = {
val ys = collection.mutable.Buffer[Int]()
var prev = xs.head
var count = 1
for (x <- xs.tail) {
if (x != prev) {
ys += count
prev = x
count = 1
}
else count += 1
}
ys += count
ys.toList
}