Recurse through Map - scala

How can I recurse through a Map?
I'm looking for something similar to list recursion, shown below.
def count(list: List[Int]): Int = {
def go(list: List[Int], acc: Int)) = {
case x :: xs => go(xs, x + sum)
case Nil => sum
}
go(list, 0)
}
Please ignore the fact that fold or reduce could be used here. I'm mentioning this tail-recursive function as a sample as to what I'd like for recursing through a map. I want to be able to append to an accumulator argument when recursing through a map.

You can turn the Map into a Seq with .toSeq or .toList or similar, or you can define your own Map extractor, but the easiest is to just use head and tail directly.
def recursive[A, B](map: Map[A, B]): Int =
if (map.isEmpty) 0 else helper(map)
def helper[A, B](map: Map[A, B]): Int = (map.head, map.tail) match {
case ((a, b), xs) if xs.isEmpty => 1
case ((a, b), xs) => 1 + helper(xs)
}

Related

Scala Tail Recursion From a Flatmap

I have a recursive call as defined below:
def getElems[A](a: A)(f: A => List[A]): List[A] = {
f(a)
}
def parse[A](depth: Int, elems: List[A], f: A => List[A]): List[A] = {
elems.flatMap(elem => {
if (depth > 0) {
parse(depth - 1, getElems(elem)(f), f)
} else elems
})
}
As it can be seen that for every elem in the elems, I run a function that in turn gives me back another List. I do this until I reach the depth 0. So for example., I start with a certain elems and a certain depth like:
parse(depth = 2, elems = List("1", "2"), someFnThatGivesBackAListOfString)
What I'm doing with my code above is that for each element in elems, I check the depth value and if the depth is > 0, I run the function for that elem and go over the same process until I hit a depth of 0. This works as expected, but as it can be seen that it is not stack safe, I'm thiking of getting a tail recursive implementation. To my understanding tail recursion is about reduction, but here it is not the case. So how do I make it stack safe or how can I do a tail recursive logic here?
I started with something like this, but this is not quite right:
def firstAttempt[A](ls: List[A], depthOrig: Int)(f: (A => List[A])): List[A] = {
#annotation.tailrec
def helper(acc: List[A], ls: List[A], depth: Int): List[A] =
ls match {
case Nil => acc
case sublist # (head :: tail) =>
// Check if the entry is available in the bloom filter
if (depth > 0)
helper(acc ::: f(head), tail, depth - 1)
else
helper(acc.appended(head), tail, depthOrig)
}
helper(Nil, ls, depthOrig)
}
I got this to work by attaching the current depth to each element.
def parse[A](depth:Int, elems:List[A], f:A => List[A]): List[A] = {
#annotation.tailrec
def loop(todo:List[(A,Int)], acc:List[A]): List[A] = todo match {
case Nil => acc
case (_,dpth)::_ if dpth < 1 =>
val (zs, td) = todo.span(_._2 < 1)
loop(td, acc ++ zs.flatMap(_ => zs.map(_._1)))
case (elm,dpth)::tl =>
loop(f(elm).map(_ -> (dpth-1)) ++ tl, acc)
}
loop(elems.map(_ -> depth), Nil)
}

Scala cats trampoline

The test("ok") is copied from book "scala with cats" by Noel Welsh and Dave Gurnell pag.254 ("D.4 Safer Folding using Eval
"), the code run fine, it's the trampolined foldRight
import cats.Eval
test("ok") {
val list = (1 to 100000).toList
def foldRightEval[A, B](as: List[A], acc: Eval[B])(fn: (A, Eval[B]) => Eval[B]): Eval[B] =
as match {
case head :: tail =>
Eval.defer(fn(head, foldRightEval(tail, acc)(fn)))
case Nil =>
acc
}
def foldRight[A, B](as: List[A], acc: B)(fn: (A, B) => B): B =
foldRightEval(as, Eval.now(acc)) { (a, b) =>
b.map(fn(a, _))
}.value
val res = foldRight(list, 0L)(_ + _)
assert(res == 5000050000l)
}
The test("ko") returns same values of test("ok") for small list but for long list the value is different. Why?
test("ko") {
val list = (1 to 100000).toList
def foldRightSafer[A, B](as: List[A], acc: B)(fn: (A, B) => B): Eval[B] = as match {
case head :: tail =>
Eval.defer(foldRightSafer(tail, acc)(fn)).map(fn(head, _))
case Nil => Eval.now(acc)
}
val res = foldRightSafer(list, 0)((a, b) => a + b).value
assert(res == 5000050000l)
}
This is #OlegPyzhcov's comment, converted into a community wiki answer
You forgot the L in 0L passed as second argument to foldRightSafer.
Because of that, the inferred generic types of the invocation are
foldRightSafer[Int, Int]((list : List[Int]), (0: Int))((_: Int) + (_: Int))
and so your addition overflows and gives you something smaller than 2000000000 (9 zeroes, Int.MaxValue = 2147483647).

Implement fold with for-comprehension

How can a fold be implemented as a for-comprehension in Scala? I see the only way is to use some recursive call? This is a try that is failing, not sure how to do this? What is the best way to implement fold as a for-comprehension
val nums = List(1,2,3)
nums.fold(0)(_+_)
def recFold(acc: Int = 0): Int = {
(for {
a <- nums
b = recFold(a + acc)
} yield b).head
}
recFold(0) //Stack overflow
If you really want to use for, you don't need recursion, but you would need a mutable variable:
val nums = List(1,2,3)
def recFold(zero: Int)(op: (Int, Int) => Int): Int = {
var result: Int = zero
for { a <- nums } result = op(result, a)
result
}
recFold(0)(_ + _) // 6
Which is pretty similar to how foldLeft is actually implemented in TraversableOnce:
def foldLeft[B](z: B)(op: (B, A) => B): B = {
var result = z
this foreach (x => result = op(result, x))
result
}
Fold can be implemented both ways right to left or left to right. No need to use for plus recursion. Recursion is enough.
def foldRight[A, B](as: List[A], z: B)(f: (A, B) => B): B = {
as match {
case Nil => z
case x :: xs => f(x, foldRight(xs, z)(f))
}
}
#annotation.tailrec
def foldLeft[A, B](as: List[A], z: B)(f: (A, B) => B): B = {
as match {
case Nil => z
case x :: xs => foldLeft(xs, f(x, z))(f)
}
}

Difficulty understanding this type signature

merge sort type signature :
def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T] = {
The function is called using :
msort[Int]((a, b) => a < b) _
Does the type msort[Int] type the parameters a & b to Int ?
To better understand this type signature I've tried to extract the less function :
def lessFunc[Int]((a , b) : (Int , Int)) : Boolean = {
true
}
But this is not correct ?
Entire code :
def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T] = {
def merge(xs: List[T], ys: List[T], acc: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys.reverse ::: acc
case (_, Nil) => xs.reverse ::: acc
case (x :: xs1, y :: ys1) =>
if (less(x, y)) merge(xs1, ys, x :: acc)
else merge(xs, ys1, y :: acc)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(less)(ys), msort(less)(zs), Nil).reverse
}
}
This is a function which takes two lists of parameters. The first list contains a less function, which as you've guessed correctly when invoked with [Int] is typing the parameters to Int.
You have just expanded it wrong. What you should have done is
def less(a: Int, b: Int) = true
or to match your anonymous function
def less(a: Int, b: Int) = a < b
Now when you call your msort like msort[Int](less) _ (see currying) you'll get a new function which is able to sort Lits[Int].
val listSorter = msort[Int](less) _
listSorter(List(1, 2, 3))
def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T]
is a function with two parameter lists that returns List of type T. First parentheses let you pass a function that will be used for sorting the list.
(T,T) => Boolean - means that the function will take two parameters and yield boolean.
The second parentheses take a List of type T . This T after name of the function is like generics in Java. You use it to pass a type. It can be called like:
def msort[String]((a,b) => a.length < b.length)(some list) if you want to sort List of String's by their length. Or you can call it like in the example to sort List of Ints
def msort[Int]((a,b) => a < b)(some list)
Because function is defined with two sets of parameters we can take advantage of it by applying only part of them and build specialised functions based on that one. Like for example:
val stringSort = msort[String]((a,b) => a.length < b.length) _
val ascendingIntSort = msort[Int]((a,b) => a < b) _
These are curried functions because stringSort's signature is List[Strint] => List[String]. Now you can reuse these methods by passing only instances of Lists to them:
stringSort(List("cat", "elephant", "butterfly"))
ascendingIntSort(List(4,1,3,2))

Performance consideration between /: and :\ operators in Scala

I feel insertSortRight is less efficient than insertSortLeft because insertSortRight needs to call List.last (which is O(n)) as one of the arguments to insert(), where insertSortLeft calls List.head (which is O(1)) as one of the arguments to insert().
Is this understanding correct? Thanks.
def insertSortRight(unsorted: List[Int]) : List[Int] = {
(unsorted :\ List[Int]()) ((a, b) => insert(a, b))
}
def insertSortLeft(unsorted: List[Int]) : List[Int] = {
(List[Int]() /: unsorted) ((a, b) => insert(b, a))
}
def insert(a: Int, list: List[Int]) : List[Int] = list match {
case List() => List(a)
case y::ys => if (a > y) y::insert(a, ys) else a::y::ys
}
DHG answered "always prefer left folding". But, Programming in Scala has an example the other way.
def flattenLeft[T](xss: List[List[T]]) = (List[T]() /: xss) (_ ::: )
def flattenRight[T](xss: List[List[T]]) = (xss :~List[T]()) ( ::: _)
I guess that is because flattenRight in this case is achieved by just one function call, while flattenLeft is achieved by n function call?
So, for a List, since head operations are desired, foldLeft is the natural choice. That way you work through the list from left to right, always taking the head. As you can see, its implementation (on LinearSeqOptimized) simply uses a while-loop and traverses once.
override /*TraversableLike*/
def foldLeft[B](z: B)(f: (B, A) => B): B = {
var acc = z
var these = this
while (!these.isEmpty) {
acc = f(acc, these.head)
these = these.tail
}
acc
}
It seems like 'foldRight' would be O(n^2) since, in order to take the last element, you have to traverse the n elements of the List n times, but the library actually optimizes this for you. Behind the scenes, foldRight is implemented like this (also on LinearSeqOptimized):
def foldRight[B](z: B)(f: (A, B) => B): B =
if (this.isEmpty) z
else f(head, tail.foldRight(z)(f))
As you can see, this function is constructed by recursively calling foldRight on the tail, holding each head on the stack, and applying the function to each head in reverse order after reaching the last element.