Scala Tail Recursive to Not Tail Recursive - scala

This may be a weird question but...
Question:
How do I turn a tail-recursive function in Scala into a non-tail-recursive solution?
Note: I am aware tail recursive solutions are great in Scala, but I was asked to change it into a non-tail recursive solution. I have no idea how to do that
I have my code for a tail-recursive solution here (at least I hope it's tail recursive lol)
def cubesTailRecur(a: List[Int], acc: List[Int] = List.empty): List[Int] = {
a match {
case Nil => acc
case h :: t if (h%2 == 0) => cubesTailRecur(t, acc)
case h :: t => cubesTailRecur(t, acc :+ Math.pow(h, 3).toInt)
}
}
What my function does is iterate through a given List of integers and returns a new array with the cubes of all the odd numbers.
Example:
println(cubesTailRecur(List(1, 2, 3, 4, 5, 6, 7)))
// OUTPUT
// List(1, 27, 125, 343)

Tail recursion is a form of recursion in which recursive call is the last instruction. To not make something tail recursive would mean that you need to do some other computation with the result of the recursive call.
In your case, you can remove the acc/accumulator parameter and perform accumulation through recursive stack. Something along the following lines,
def cubesRec(a: List[Int]): List[Int] = a match {
case Nil => List[Int]()
case h::t if (h%2 == 0) => cubesRec(t)
case h::t => Math.pow(h,3).toInt :: cubesRec(t)
}

Related

How do you write a function to divide the input list into three sublists?

Write a function to divide the input list into three sublists.
The first sub-list is to include all the elements whose indexes satisfy the equation i mod 3 = 1.
The second sub-list is to include all the elements whose indexes satisfy the equation and mod 3 = 2.
The third sub-list is to contain the remaining elements.
The order of the elements must be maintained. Return the result as three lists.
Write a function using tail and non-tail recursion.
My attempt: I’m very confused in how to increase index so it can go through the list, any recommendation about how to make it recursive with increasing index each time?
def divide(list: List[Int]): (List[Int], List[Int], List[Int]) = {
var index:Int =0
def splitList(remaining: List[Int], firstSubList: List[Int], secondSubList: List[Int], thirdSubList: List[Int], index:Int): (List[Int], List[Int], List[Int]) = {
if(remaining.isEmpty) {
return (List[Int](), List[Int](), List[Int]())
}
val splitted = splitList(remaining.tail, firstSubList, secondSubList, thirdSubList, index)
val firstList = if (index % 3 == 1) List() ::: splitted._1 else splitted._1
val secondList = if (index % 3 == 2) List() ::: splitted._2 else splitted._2
val thirdList = if((index% 3 != 1) && (index % 3 != 2)) List() ::: splitted._3 else splitted._3
index +1
(firstSubList ::: firstList, secondSubList ::: secondList, thirdSubList ::: thirdList)
}
splitList(list, List(), List(), List(), index+1)
}
println(divide(List(0,11,22,33)))
Generalizing the requirement a little, here's one approach using a simple recursive function to compose a Map of Lists by modulo n of the original list indexes:
def splitList[T](list: List[T], n: Int): Map[Int, List[T]] = {
#scala.annotation.tailrec
def loop(zls: List[(T, Int)], lsMap: Map[Int, List[T]]): Map[Int, List[T]] =
zls match {
case Nil =>
lsMap.map{ case (i, ls) => (i, ls.reverse) }
case (x, i) :: rest =>
val j = i % n
loop(rest, lsMap + (j -> (x :: lsMap.getOrElse(j, Nil))))
}
loop(list.zipWithIndex, Map.empty[Int, List[T]])
}
splitList(List(0, 11, 22, 33, 44, 55, 66), 3)
// Map(0 -> List(0, 33, 66), 1 -> List(11, 44), 2 -> List(22, 55))
splitList(List('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'), 4)
// Map(0 -> List(a, e, i), 1 -> List(b, f), 2 -> List(c, g), 3 -> List(d, h))
To do this in real life, just label each value with its index and then group by that index modulo 3:
def divide[T](list: List[T]) = {
val g = list.zipWithIndex.groupMap(_._2 % 3)(_._1)
(g.getOrElse(1, Nil), g.getOrElse(2, Nil), g.getOrElse(0, Nil))
}
If you insist on a recursive version, it might look like this:
def divide[T](list: List[T]) = {
def loop(rem: List[T]): (List[T], List[T], List[T]) =
rem match {
case a::b::c::tail =>
val rem = loop(tail)
(b +: rem._1, c +: rem._2, a +: rem._3)
case a::b::Nil =>
(List(b), Nil, List(a))
case a::Nil =>
(Nil, Nil, List(a))
case Nil =>
(Nil, Nil, Nil)
}
loop(list)
}
Tail recursion would look like this:
def divide[T](list: List[T]) = {
#annotation.tailrec
def loop(rem: List[T], res: (List[T], List[T], List[T])): (List[T], List[T], List[T]) =
rem match {
case a::b::c::tail =>
loop(tail, (res._1 :+ b, res._2 :+ c, res._3 :+ a))
case a::b::Nil =>
(res._1 :+ b, res._2, res._3 :+ a)
case a::Nil =>
(res._1, res._2, res._3 :+ a)
case Nil =>
res
}
loop(list, (Nil, Nil, Nil))
}
And if you care about efficiency, this version would build the lists in the other order and reverse them when returning the result.
Your problem is that you put index+1 into a wrong place. Try swapping it around: put index+1 into the call where you have index, and index into the other one. Also remove the "standalone" index+1 statement in the middle, it doesn't do anything anyway.
That should make your code work ... but it is still not very good. A couple of problems with it (besides it being badly structured, non-idiomatic, and hard to read, which is kinda subjective):
It it is not tail-recursive, and effectively, creates another copy of the entire list on stack. This may be problematic when the list is long.
It concatenates (potentially long) lists. This is a bad idea. List in scala is a singly linked list, you have it's head readily available, but to get to the end, you need to spend O(N) cycles, iterating through each node. Thus things like foo:::bar in a iterative function instantly make any algorithm (at least) quadratic.
The usual "trick" to avoid the last problem is prepending elements to output one-by-one, and then reversing the result in the end. The first one can be avoided with tail-recursion. The "non-idiomatic" and "hard to read" problems are mostly addressed by using match statement in this case:
def split3(
in: List[Int],
one: List[Int],
two: List[Int],
three: List[Int],
index: Int = 0
} = (in, index % 3) match {
case (Nil, _) => (one.reverse, two.reverse, three.reverse)
case (head::tail, 1) => split3(tail, head::one, two, three, index+1)
case (head::tail, 2) => split3(tail, one, head::two, three, index+1)
case (head::tail, _) => split3(tail, one, two, head::three, index+1)
}
Now, this is a fine solution, albeit a little repetitive to my demanding eye ... But if want to be clever and really unleash the full power of scala standard library, forget recursion, you don't really need it in this case.
If you knew that number of elements in the list was always divisible by 3,
you could just do list.grouped(3).toSeq.transpose: break the list into groups of three (each group will have index%3=0 as first element, index%3=1 as second, index%3=2 as the third), and then transpose will turn a list of lists of 3 into a list of three lists where the first one contains all the first elements, the second - all the seconds etc. (I know, you wanted them in a different order, but that's trivial). If you are having trouble understanding what I am talking about, just try running it on some lists, and look at the results.
This would be a really elegant solution ... if it worked :/ The problem is, that it only does when you have 3*n elements in the original list. If not, transpose will fail on the last element if it doesn't have 3 elements like all others. Can we fix it? Well ... that's where the cleverness comes in.
val (triplets, tails) = list.grouped(3).toSeq.partition(_.size == 3)
triplets
.transpose
.padTo(3, Nil)
.zip(tails.flatten.map(Seq(_)).padTo(3, Nil))
.map { case (head, tail) => head ++ tail }
Basically, it is doing the same thing as the one-liner I described above (break into groups of 3 and transpose), but adds special handling for the case when the last group has less than three elements - it splits it out and pads with required number of empty lists, then just appends the result to transposed triplets.

Function takes two List[Int] arguments and produces a List[Int]. SCALA [duplicate]

This question already has answers here:
Scala - Combine two lists in an alternating fashion
(4 answers)
Closed 3 years ago.
The elements of the resulting list should alternate between the elements of the arguments. Assume that the two arguments have the same length.
USE RECURSION
My code as follows
val finalString = new ListBuffer[Int]
val buff2= new ListBuffer[Int]
def alternate(xs:List[Int], ys:List[Int]):List[Int] = {
while (xs.nonEmpty) {
finalString += xs.head + ys.head
alternate(xs.tail,ys.tail)
}
return finalString.toList
}
EXPECTED RESULT:
alternate ( List (1 , 3, 5) , List (2 , 4, 6)) = List (1 , 2, 3, 4, 6)
As far for the output, I don't get any output. The program is still running and cannot be executed.
Are there any Scala experts?
There are a few problems with the recursive solutions suggested so far (including yours, which would actually work, if you replace while with if): appending to end of list is a linear operation, making the whole thing quadratic (taking a .length of a list too, as well ас accessing elements by index), don't do that; also, if the lists are long, a recursion may require a lot of space on the stack, you should be using tail-recursion whenever possible.
Here is a solution that is free of both those problems: it builds the output backwards, by prepending elements to the list (constant time operation) rather than appending them, and reverses the result at the end. It is also tail-recursive: the recursive call is the last operation in the function, which allows the compiler to convert it into a loop, so that it will only use a single stack frame for execution regardless of the size of the lists.
#tailrec
def alternate(
a: List[Int],
b: List[Int],
result: List[Int] = Nil
): List[Int] = (a,b) match {
case (Nil, _) | (_, Nil) => result.reversed
case (ah :: at, bh :: bt) => alternate(at, bt, bh :: ah :: result)
}
(if the lists are of different lengths, the whole thing stops when the shortest one ends, and whatever is left in the longer one is thrown out. You may want to modify the first case (split it into two, perhaps) if you desire a different behavior).
BTW, your own solution is actually better than most suggested here: it is actually tail recursive (or rather can be made one if you add else after your if, which is now while), and appending to ListBuffer isn't actually as bad as to a List. But using mutable state is generally considered "code smell" in scala, and should be avoided (that's one of the main ideas behind using recursion instead of loops in the first place).
Condition xs.nonEmpty is true always so you have infinite while loop.
Maybe you meant if instead of while.
A more Scala-ish approach would be something like:
def alternate(xs: List[Int], ys: List[Int]): List[Int] = {
xs.zip(ys).flatMap{case (x, y) => List(x, y)}
}
alternate(List(1,3,5), List(2,4,6))
// List(1, 2, 3, 4, 5, 6)
A recursive solution using match
def alternate[T](a: List[T], b: List[T]): List[T] =
(a, b) match {
case (h1::t1, h2::t2) =>
h1 +: h2 +: alternate(t1, t2)
case _ =>
a ++ b
}
This could be more efficient at the cost of clarity.
Update
This is the more efficient solution:
def alternate[T](a: List[T], b: List[T]): List[T] = {
#annotation.tailrec
def loop(a: List[T], b: List[T], res: List[T]): List[T] =
(a, b) match {
case (h1 :: t1, h2 :: t2) =>
loop(t1, t2, h2 +: h1 +: res)
case _ =>
a ++ b ++ res.reverse
}
loop(a, b, Nil)
}
This retains the original function signature but uses an inner function that is an efficient, tail-recursive implementation of the algorithm.
You're accessing variables from outside the method, which is bad. I would suggest something like the following:
object Main extends App {
val l1 = List(1, 3, 5)
val l2 = List(2, 4, 6)
def alternate[A](l1: List[A], l2: List[A]): List[A] = {
if (l1.isEmpty || l2.isEmpty) List()
else List(l1.head,l2.head) ++ alternate(l1.tail, l2.tail)
}
println(alternate(l1, l2))
}
Still recursive but without accessing state from outside the method.
Assuming both lists are of the same length, you can use a ListBuffer to build up the alternating list. alternate is a pure function:
import scala.collection.mutable.ListBuffer
object Alternate extends App {
def alternate[T](xs: List[T], ys: List[T]): List[T] = {
val buffer = new ListBuffer[T]
for ((x, y) <- xs.zip(ys)) {
buffer += x
buffer += y
}
buffer.toList
}
alternate(List(1, 3, 5), List(2, 4, 6)).foreach(println)
}

Scala - finding a specific tuple in a list

Let's say we have this list of tuples:
val data = List(('a', List(1, 0)), ('b', List(1, 1)), ('c', List(0)))
The list has this signature:
List[(Char, List[Int])]
My task is to get the "List[Int]" element from a tuple inside "data" whose key is, for instance, letter "b". If I implement a method like "findIntList(data, 'b')", then I expect List(1, 1) as a result. I have tried the following approaches:
data.foreach { elem => if (elem._1 == char) return elem._2 }
data.find(x=> x._1 == ch)
for (elem <- data) yield elem match {case (x, y: List[Bit]) => if (x == char) y}
for (x <- data) yield if (x._1 == char) x._2
With all the approaches (except Approach 1, where I employ an explicit "return"), I get either a List[Option] or List[Any] and I don't know how to extract the "List[Int]" out of it.
One of many ways:
data.toMap.get('b').get
toMap converts a list of 2-tuples into a Map from the first element of the tuples to the second. get gives you the value for the given key and returns an Option, thus you need another get to actually get the list.
Or you can use:
data.find(_._1 == 'b').get._2
Note: Only use get on Option when you can guarantee that you'll have a Some and not a None. See http://www.scala-lang.org/api/current/index.html#scala.Option for how to use Option idiomatic.
Update: Explanation of the result types you see with your different approaches
Approach 2: find returns an Option[List[Int]] because it can not guarantee that a matching element gets found.
Approach 3: here you basically do a map, i.e. you apply a function to each element of your collection. For the element you are looking for the function returns your List[Int] for all other elements it contains the value () which is the Unit value, roughly equivalent to void in Java, but an actual type. Since the only common super type of ´List[Int]´ and ´Unit´ is ´Any´ you get a ´List[Any]´ as the result.
Approach 4 is basically the same as #3
Another way is
data.toMap.apply('b')
Or with one intermediate step this is even nicer:
val m = data.toMap
m('b')
where apply is used implicitly, i.e., the last line is equivalent to
m.apply('b')
There are multiple ways of doing it. One more way:
scala> def listInt(ls:List[(Char, List[Int])],ch:Char) = ls filter (a => a._1 == ch) match {
| case Nil => List[Int]()
| case x ::xs => x._2
| }
listInt: (ls: List[(Char, List[Int])], ch: Char)List[Int]
scala> listInt(data, 'b')
res66: List[Int] = List(1, 1)
You can try something like(when you are sure it exists) simply by adding type information.
val char = 'b'
data.collect{case (x,y:List[Int]) if x == char => y}.head
or use headOption if your not sure the character exists
data.collect{case (x,y:List[Int]) if x == char => y}.headOption
You can also solve this using pattern matching. Keep in mind you need to make it recursive though. The solution should look something like this;
def findTupleValue(tupleList: List[(Char, List[Int])], char: Char): List[Int] = tupleList match {
case (k, list) :: _ if char == k => list
case _ :: theRest => findTupleValue(theRest, char)
}
What this will do is walk your tuple list recursively. Check whether the head element matches your condition (the key you are looking for) and then returns it. Or continues with the remainder of the list.

How to write the following snippet in a correct Scala functional way?

I'm very new to Scala and wanted to know if this is the correct way of writing:
def createCol(prior: List[Int], current: List[Int]): List[Int] = {
if (prior.isEmpty) List(1) ++ current
else if (prior.tail.isEmpty) // begin of the block to improve
createCol(prior.tail, current ++ List(prior.head))
else
createCol(prior.tail, current ++ List(prior.head + prior.tail.head))
}
The part I'm interested in is this:
if (prior.tail.isEmpty)
createCol(prior.tail, current ++ List(prior.head))
else
createCol(prior.tail, current ++ List(prior.head + prior.tail.head))
As I'm repeating almost the same function call createCol so I tried this instead:
val ssum = if (prior.tail.isEmpty) prior.head else prior.head + prior.tail.head
createCol(prior.tail, current ++ List(ssum))
What's the best or recommended way of doing it?
Thanks
A few points:
I changed your function to use Scala's pattern-matching framework since it greatly simplifies your code.
You shouldn't do List(x) ++ someList because this constructs a single-item list unnecessarily. You should just use the prepend method :: (or +:). Same goes for appending (:+).
If prior only has one element, you know that all the recursive call is going to do is prepend 1 to the front of current. So you can drop the recursive call from the second case.
Your method is tail-recursive, so annotate it with #tailrec.
Finally, consider using a Vector instead of List. Appending to a List is O(n) because the method must traverse all the way to the end (and then reconstruct the List from the back to the front). But both prepending and appending to a Vector are effectively O(1).
So:
#tailrec
def createCol(prior: List[Int], current: List[Int]): List[Int] = {
prior match {
case Nil => 1 :: current
case head :: Nil => 1 +: current :+ head
case head :: tail => createCol(tail, current :+ (head + tail.head))
}
}
You could also do it in two cases, like you described in your question. But you should use the headOption method instead of explicitly doing an if/else:
#tailrec
def createCol(prior: List[Int], current: List[Int]): List[Int] = {
prior match {
case Nil =>
1 :: current
case head :: tail =>
createCol(tail, current ++ List(head + tail.headOption.getOrElse(0)))
}
}
Your function seems to be equivalent to the following:
def createCol(prior: List[Int], current: List[Int]) =
if (prior.isEmpty) 1 :: current
else 1 :: current ::: (prior, prior.tail :+ 0).zipped.map(_ + _)
Or with Vector which should yield better performance for prepend and append if the lists are long:
def createCol(prior: Vector[Int], current: Vector[Int]) =
if (prior.isEmpty) 1 +: current
else (1 +: current) ++ (prior, prior.tail :+ 0).zipped.map(_ + _)
That avoids recursion and I think it's clearer to see that current is not modified, that 1 is just prepended regardless and that prior is summed with itself with an offset of 1 with the last element by itself (summed with 0) and then appended to current.
Or even to avoid the repetition of (1 +: current):
(1 +: current) ++ (
if (prior.isEmpty) Vector()
else (prior, prior.tail :+ 0).zipped.map(_ + _))

Pattern matching and infinite streams

So, I'm working to teach myself Scala, and one of the things I've been playing with is the Stream class. I tried to use a naïve translation of the classic Haskell version of Dijkstra's solution to the Hamming number problem:
object LazyHammingBad {
private def merge(a: Stream[BigInt], b: Stream[BigInt]): Stream[BigInt] =
(a, b) match {
case (x #:: xs, y #:: ys) =>
if (x < y) x #:: merge(xs, b)
else if (y < x) y #:: merge(a, ys)
else x #:: merge(xs, ys)
}
val numbers: Stream[BigInt] =
1 #:: merge(numbers map { _ * 2 },
merge(numbers map { _ * 3 }, numbers map { _ * 5 }))
}
Taking this for a spin in the interpreter led quickly to disappointment:
scala> LazyHammingBad.numbers.take(10).toList
java.lang.StackOverflowError
I decided to look to see if other people had solved the problem in Scala using the Haskell approach, and adapted this solution from Rosetta Code:
object LazyHammingGood {
private def merge(a: Stream[BigInt], b: Stream[BigInt]): Stream[BigInt] =
if (a.head < b.head) a.head #:: merge(a.tail, b)
else if (b.head < a.head) b.head #:: merge(a, b.tail)
else a.head #:: merge(a.tail, b.tail)
val numbers: Stream[BigInt] =
1 #:: merge(numbers map {_ * 2},
merge(numbers map {_ * 3}, numbers map {_ * 5}))
}
This one worked nicely, but I still wonder how I went wrong in LazyHammingBad. Does using #:: to destructure x #:: xs force the evaluation of xs for some reason? Is there any way to use pattern matching safely with infinite streams, or do you just have to use head and tail if you don't want things to blow up?
a match {case x#::xs =>... is about the same as val (x, xs) = (a.head, a.tail). So the difference between the bad version and the good one, is that in that in the bad version, you're calling a.tail and b.tail right at the start, instead of just use them to build the tail of the resulting stream. Furthermore when you use them at the right of #:: (not pattern matching, but building the result, as in #:: merge(a.b.tail) you are not actually calling merge, that will be done only later, when accessing the tail of the returned Stream. So in the good version, a call to merge does not call tail at all. In the bad version, it calls it right at start.
Now if you consider numbers, or even a simplified version, say 1 #:: merge(numbers, anotherStream), when you call you call tail on that (as take(10) will), merge has to be evaluated. You call tail on numbers, which call merge with numbers as parameters, which calls tails on numbers, which calls merge, which calls tail...
By contrast, in super lazy Haskell, when you pattern match, it does barely any work. When you do case l of x:xs, it will evaluate l just enough to know whether it is an empty list or a cons.
If it is indeed a cons, x and xs will be available as two thunks, functions that will eventually give access, later, to content. The closest equivalent in Scala would be to just test empty.
Note also that in Scala Stream, while the tail is lazy, the head is not. When you have a (non empty) Stream, the head has to be known. Which means that when you get the tail of the stream, itself a stream, its head, that is the second element of the original stream, has to be computed. This is sometimes problematic, but in your example, you fail before even getting there.
Note that you can do what you want by defining a better pattern matcher for Stream:
Here's a bit I just pulled together in a Scala Worksheet:
object HammingTest {
// A convenience object for stream pattern matching
object #:: {
class TailWrapper[+A](s: Stream[A]) {
def unwrap = s.tail
}
object TailWrapper {
implicit def unwrap[A](wrapped: TailWrapper[A]) = wrapped.unwrap
}
def unapply[A](s: Stream[A]): Option[(A, TailWrapper[A])] = {
if (s.isEmpty) None
else {
Some(s.head, new TailWrapper(s))
}
}
}
def merge(a: Stream[BigInt], b: Stream[BigInt]): Stream[BigInt] =
(a, b) match {
case (x #:: xs, y #:: ys) =>
if (x < y) x #:: merge(xs, b)
else if (y < x) y #:: merge(a, ys)
else x #:: merge(xs, ys)
} //> merge: (a: Stream[BigInt], b: Stream[BigInt])Stream[BigInt]
lazy val numbers: Stream[BigInt] =
1 #:: merge(numbers map { _ * 2 }, merge(numbers map { _ * 3 }, numbers map { _ * 5 }))
//> numbers : Stream[BigInt] = <lazy>
numbers.take(10).toList //> res0: List[BigInt] = List(1, 2, 3, 4, 5, 6, 8, 9, 10, 12)
}
Now you just need to make sure that Scala finds your object #:: instead of the one in Stream.class whenever it's doing pattern matching. To facilitate that, it might be best to use a different name like #>: or ##:: and then just remember to always use that name when pattern matching.
If you ever need to match the empty stream, use case Stream.Empty. Using case Stream() will attempt to evaluate your entire stream there in the pattern match, which will lead to sadness.