I have a code in scala that I wrote but I would like to eliminate ++ from it. The code runs fine but I'm trying not to use ++ or any built in functions or operators (not even :::).
Is it just better to create a val, or are there better ways around it.
Here's a sample of that code.
def partitionAux[A](f: A => Boolean, lst: List[A],
rslt: (List[A], List[A]) ):(List[A], List[A]) = {
lst match {
case Nil => return result
case head :: rest => {
if (f(head))
return partitionHelper(f, rest, (result._1 ++ List[A](head), rslt._2))
else ...
Given that you have only a single element as a second arg of ++, you could implement it yourself:
def concat[A](lst: List[A], a: A): List[A] =
lst match {
case Nil => a :: Nil
case head :: tail => head :: concat(tail, a)
}
println(concat(1 :: 2 :: 3 :: 4 :: Nil, 100)) // 1 :: 2 :: 3 :: 4 :: 100
Also given that you mentioned that partitionAux should split the list into two, it sounds like you should have just head :: result._1, instead of result._1 ++ List[A](head), and then reverse the list in the end. It is easy to write the reverse function yourself, like:
#tailRec
def reverse[A](list: List[A], result: List[A] = Nil): List[A] =
list match {
case Nil => result
case head :: tail => reverse(tail, head :: result)
}
P.S. And you don't need to put return keyword in scala. It doesn't do anything in you case
Related
I have the following snippet of scala code:
def append(as: List[Int], bs: List[Int]): List[Int] = as match {
case Nil => bs
case x::xs => x::append(xs, bs)
}
I don't understand the x:: in the line where x::append(xs, bs) is. I know that when the list as is empty then bs will be returend (with an appended as when as was not empty before). But how does scala know in the mentioned line that is should append as to bs with x::(..,..)
Perhaps it would help if we desugar append a bit
def append(as: List[Int], bs: List[Int]): List[Int] =
as match {
case Nil => bs
case ::(x, xs) =>
val list = append(xs, bs)
list.::(x)
}
Note how :: appears twice, however the first one in
case ::(x, xs)
is actually a case class, even though its symbolic name seems strange, and its declaration looks a bit like this
case class :: (head: A, next: List[A])
whilst, on the other hand, the second :: in
list.::(x)
is actually a right-associative method which Adds an element at the beginning of this list and looks something like so
def :: (elem: B): List[B]
Note how x :: list is equivalent to list.::(x) and not x.::(list) meaning :: is invoked on the right argument.
I'm working on question P07 of Ninety-Nine Scala Problems:
P07 (**) Flatten a nested list structure.
Example:
scala> flatten(List(List(1, 1), 2, List(3, List(5, 8))))
res0: List[Any] = List(1, 1, 2, 3, 5, 8)
My initial attempt at a solution was:
def flatten[A](ls : List[A]): List[A] = {
def flattenRec[A](ls: List[A], flatList: List[A]): List[A] = ls match {
case Nil => flatList
case head: List[A] :: tail => flattenRec(head ::: flatten(tail), flatList)
case head :: tail => flattenRec(tail, flatList :+ head)
}
flattenRec(ls, List[A]())
}
however this doesn't compile as I'm not allowed to specify a type for head in the second case statement. Is there a way for me to do this?
As an aside, the recommended solution uses flatMap instead of match, but I'm not sure why it even needs pattern matching in that case...
You can just bracket the declaration of head:
def flatten[A](ls : List[A]): List[A] = {
def flattenRec[A](ls: List[A], flatList: List[A]): List[A] = ls match {
case Nil => flatList
case (head: List[A]) :: tail => flattenRec(head, flatList)
case head :: tail => flattenRec(tail, flatList :+ head)
}
flattenRec(ls, List[A]())
}
Note that you will get a warning about the type pattern being unchecked (because the fact that head needs to be a list of A and not anything else will be lost at runtime due to erasure), which you will need to assure yourself you can ignore (or run through some hijinks involving TypeTags).
Nice problem and an alternate solution below:
def flatten(a:List[Any]):List[Any] =
a.flatMap{
case l:List[Any] => flatten(l)
case l => List(l)
}
If the last statement in a function is func(x,tailList):
def func(x:Int):List[Int]...
case head :: tailList => head :: func(x,tailList)
converting this function to tail recursion requires accumulator to be added as a third parameter (and to keep it clean adding a local function inside func() ).
insertTail(x,tailList,head::acc)
doesn't seem to work correctly. shouldn't "acc" hold the computation in progress?
Am I missing something here to make it tail recursive work with accumulator?
Adding a more complete example
def funcTailTest(x:Int,xs:List[Int]):List[Int] = {
#tailrec
def inner(x:Int,xs:List[Int],acc:List[Int]) : List[Int] = xs match {
case head::tailList => {
inner(x,tailList,head::acc)
}
}
inner(x,xs,Nil)
}
basically head should be added to the output of inner() function so w/o an attempt to make it tail recursive last statement in a case will look
head::inner(x,tailList)
Assuming that reverse is also tail recursively implemented (which it definitely can be), the following is a tail recursive append:
def append[T](y: T, xs: List[T]): List[T] = {
#tailrec
def appendAcc[T](y: T, xs: List[T], acc: List[T]): List[T] = xs match {
case Nil => y :: acc
case x :: xs => appendAcc(y, xs, x :: acc)
}
appendAcc(y, xs, Nil).reverse
}
Following is a scala function to implement Tail recursion using cons operator
def reverseUtility(ele: List[Int], res: List[Int]):List[Int] ={
ele match {
case Nil => Nil
case x :: Nil => x :: res
case x :: y => reverseUtility(y, (x::res))
}}
Pass a list of Int and an empty list called res(result) as parameters for the function. Time complexity for the function is O(N)
I'm having a look at the following code
http://aperiodic.net/phil/scala/s-99/p26.scala
Specifically
def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
ls match {
case Nil => Nil
case sublist#(_ :: tail) => f(sublist) ::: flatMapSublists(tail)(f)
}
I'm getting a StackOverflowError for large values presumably because the function is not tail recursive. Is there a way to transform the function to accommodate large numbers?
It is definitely not tail recursive. The f(sublist) ::: is modifying the results of the recursive call, making it a plain-old-stack-blowing recursion instead of a tail recursion.
One way to ensure that your functions are tail recursive is to put the #annotation.tailrec on any function that you expect to be tail recursive. The compiler will report an error if it fails to perform the tail call optimization.
For this, I would add a small helper function that's actually tail recursive:
def flatMapSublistsTR[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] = {
#annotation.tailrec
def helper(r: List[B], ls: List[A]): List[B] = {
ls match {
case Nil => r
case sublist#(_ :: tail) => helper(r ::: f(sublist), tail)
}
}
helper(Nil, ls)
}
For reasons not immediately obvious to me, the results come out in a different order than the original function. But, it looks like it works :-) Fixed.
Here is another way to implement the function:
scala> def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
| List.iterate(ls, ls.size)(_.tail).flatMap(f)
flatMapSublists: [A, B](ls: List[A])(f: List[A] => List[B])List[B]
A simply comparison between dave's flatMapSublistsTR and mine:
scala> def time(count: Int)(call : => Unit):Long = {
| val start = System.currentTimeMillis
| var cnt = count
| while(cnt > 0) {
| cnt -= 1
| call
| }
| System.currentTimeMillis - start
| }
time: (count: Int)(call: => Unit)Long
scala> val xs = List.range(0,100)
scala> val fn = identity[List[Int]] _
fn: List[Int] => List[Int] = <function1>
scala> time(10000){ flatMapSublists(xs)(fn) }
res1: Long = 5732
scala> time(10000){ flatMapSublistsTR(xs)(fn) }
res2: Long = 347232
Where the method flatMapSublistsTR is implemented as:
def flatMapSublistsTR[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] = {
#annotation.tailrec
def helper(r: List[B], ls: List[A]): List[B] = {
ls match {
case Nil => r
case sublist#(_ :: tail) => helper(r ::: f(sublist), tail)
}
}
helper(Nil, ls)
}
def flatMapSublists2[A,B](ls: List[A], result: List[B] = Nil)(f: (List[A]) => List[B]): List[B] =
ls match {
case Nil => result
case sublist#(_ :: tail) => flatMapSublists2(tail, result ++ f(sublist))(f)
}
You generally just need to add a result result parameter to carry from one iteration to the next, and spit out the result at the end instead of adding the end to the list.
Also that confusting sublist# thing can be simplified to
case _ :: tail => flatMapSublists2(tail, result ++ f(ls))(f)
Off-topic: here's how I solved problem 26, without the need for helper methods like the one above. If you can make this tail-recursive, have a gold star.
def combinations[A](n: Int, lst: List[A]): List[List[A]] = n match {
case 1 => lst.map(List(_))
case _ => lst.flatMap(i => combinations (n - 1, lst.dropWhile(_ != i).tail) map (i :: _))
}
I am trying to do some examples programs in scala to get more familiar with the language, For that I am trying to re-implement some of the built in methods in Haskell, Most of these methods I am sure are also implemented in Scala too, But these are just for my practice. I think I can post some of code snippets (not all of them) to get a better way of doing things and to validate my understanding of scala. So please let me know if this is not the place to do these things.
Here is my scala implementation to get the last element of any list. Is this the right way of doing things, By using Any am I loosing the type of the object containing in the list? Is this how this kind of things implemented in scala?
def getLast(xs: List[Any]): Any = xs match {
case List() => null
case x :: List() => x
case _ :: ys => getLast(ys)
}
Parameterize the type of your function and use "Nil" instead of List() like so:
def getLast[T](xs: List[T]): T = xs match {
case Nil => null.asInstanceOf[T]
case x :: Nil => x
case _ :: ys => getLast(ys)
}
Also, consider making it return an Option type:
def getLast[T](xs: List[T]): Option[T] = xs match {
case Nil => None
case x :: Nil => Some(x)
case _ :: ys => getLast(ys)
}
Usage:
val listOfInts = List(1,2,3)
assert(getLast(listOfInts).isInstanceOf[Int])
val listOfStrings = List("one","two","three")
assert(getLast(listOfStrings).isInstanceOf[String])
Firstly, avoid the null, and especially null.asInstanceOf[T]. Observe the danger with primitives:
scala> null.asInstanceOf[Int]
res19: Int = 0
scala> null.asInstanceOf[Boolean]
res20: Boolean = false
So the signature should either be List[T] => T, whereby last on an empty iterator throws an exception:
def last[T](ts: List[T]): T = ts match {
case Nil => throw new NoSuchElementException
case t :: Nil => t
case t :: ts => last(ts)
}
Or instead: List[T] => Option[T]
def lastOption[T](ts: List[T]): Option[T] = ts match {
case Nil => None
case t :: Nil => Some(t)
case t :: ts => lastOption(ts)
}
def lastOption1[T](ts: List[T]): Option[T] = ts.reverse.headOption
def lastOptionInScala28[T](ts: List[T]): Option[T] = ts.lastOption // :)