How to write the zip function, which tuples corresponding elements in a list. I understand that zip is a built in function but I am trying to write it from scratch.
def zip[A,B](lst1: List[A], lst2: List[B]): List[(A, B)]
Test example would be:
test("zip test 1") {
assert(zip(List(1, 2, 3), List(4, 5, 6)) == List((1,4), (2, 5), (3, 6)))
}
or strings as parameters:
test("zip test 2") {
assert(zip(List("hey", "code"), List("world", "scala")) ==
List(("hey", "world"), ("code", "scala")))
}
I tried this so far:
def zip[A,B](lst1:List[A], lst2:List[B]):List[(A,B)] = (lst1,lst2) match{
case Nil=> Nil
case (h1::t1 :: h2 :: t2) =>zip(t1, t2)
}
But I get a type mismatch error, and a immutability error.
If either list is empty, return the empty list. Otherwise, prepend the pair of heads to the zip of tails:
def zip[A, B](xs: List[A], ys: List[B]): List[(A, B)] =
(xs, ys) match {
case (Nil, _) => Nil
case (_, Nil) => Nil
case (x :: xs, y :: ys) => (x, y) :: zip(xs, ys)
}
Augmenting to exploit tail recursion optimisation is left as an exercise for the reader.
Related
I have an exercise in Scala in which I have to transform that kind of list (a,a,a,b,c,d,d,e,a,a) into
((a,3),(b,1),(c,1),(d,2),(e,1),(a,2)).
I obviously know that my algorithm is not correct yet, but I wanted to start with anything.
The problem is that I don't know how to turn on the function (last line), because the error is that whatever I take as previous' argument, it says that required: A, found: Int/String etc.
The previous was meant to be as a head of the previous iteration.
def compress[A](l: List[A]): List[(A, Int)] = {
def compressHelper(l: List[A], acc: List[(A, Int)], previous: A, counter: Int): List[(A, Int)] = {
l match {
case head::tail => {
if (head == previous) {
compressHelper(tail, acc :+ (head, counter+1), head, counter+1)
}
else {
compressHelper(tail, acc :+ (head, counter), head, 1)
}
}
case Nil => acc
}
}
compressHelper(l, List(), , 1)
}
You don't need to pass previous explicitly, just look at the accumulator:
def compress[A](l: List[A], acc: List[(A, Int)]=Nil): List[(A, Int)] =
(l, acc) match {
case (Nil, _) => acc.reverse
case (head :: tail, (a, n) :: rest) if a == head =>
compress(tail, (a, n+1) :: rest)
case (head :: tail, _) => compress (tail, (head, 1) :: acc)
}
How can i achieve this? Where xs is a List[Any].
def flatten(xs: List[Any]): List[Any] = {
xs match {
case x: List[Any] :: t => flatten(x) ::: flatten(t)
case x :: t => x :: flatten(t)
case Nil => Nil
}
}
The first case does not work properly. For some reason I cannot give a type to the head of the list x.
As #Luis mentioned, this is really bad idea to use List[Any] but you still want to write flatten, then using reflection you can do like this:
val xs: List[Any] = List(List(1, 2), 3, 4)
def flatten(xs: List[Any]): List[Any] = {
xs match {
case x :: t if x.isInstanceOf[List[_]] => flatten(x.asInstanceOf[List[Any]]) ::: flatten(t)
case x :: t => x :: flatten(t)
case Nil => Nil
}
}
println(flatten(xs)) // List(1, 2, 3, 4)
I am having a real tough time with tail recursion...
My current function filters out values less than 'n' from list 'l'
def filter(n: Int, l: List): List = l match {
case Nil => Nil
case hd :: tl => {
if (hd < n) filter(n, tl)
else hd :: filter(n, tl)
}
}
When using large lists, this causes the stack to overflow.
Can someone please help me understand how to convert this to a tail recursive function?
Thanks for any input!
This is usually done with a helper function that accumulates the results. filterR has an additional parameter acc that we add values that are greater than n to.
def filter(n: Int, l: List[Int]): List[Int] = {
#scala.annotation.tailrec
def filterR(n: Int, l: List[Int], acc: List[Int]): List[Int] = l match {
case Nil => acc
case hd :: tl if(hd < n) => filterR(n, tl, acc)
case hd :: tl => filterR(n, tl, hd :: acc)
}
filterR(n, l, List[Int]())
}
With the suggestion from #jwvh:
#scala.annotation.tailrec
def filter(n: Int, l: List[Int], acc: List[Int] = List[Int]()): List[Int] = l match {
case Nil => acc.reverse
case hd :: tl if(hd < n) => filter(n, tl, acc)
case hd :: tl => filter(n, tl, hd :: acc)
}
#Brian's answer is nice but it reverses the input list. That's generally not the intended behaviour.
#jwvh's recommendation is pass the accumulator in a 3rd parameter to the function but that leaks private API to public API.
Either solution would necessitate reversing the accumulator before returning the answer – effectively iterating thru your input list twice. That's an insane implementation, especially considering you're trying to implement this to facilitate large lists.
Consider this tail-recursive implementation which does not expose private API and does not require the accumulator to be reversed after filtering.
disclaimer: this is the first scala procedure I have ever written. Feedback on any implementation style or detail is welcomed.
def filter(n: Int, xs: List[Int]): List[Int] = {
#scala.annotation.tailrec
def aux(k: List[Int] => List[Int], xs: List[Int]): List[Int] = xs match {
case Nil => k(Nil)
case x :: xs if (x < n) => aux(k, xs)
case x :: xs => aux((rest: List[Int]) => k(x :: rest), xs)
}
aux(identity, xs)
}
filter(5, List(1,2,3,4,5,6,7,8,9,0)))
// => List(5, 6, 7, 8, 9)
I'm teaching myself scala and trying to fatten my FP skills.
One of my references, Essentials of Programming Languages (available here), has a handy list of easy recursive functions. On page page 27/50, we are asked to implement swapper() function.
(swapper s1 s2 slist) returns a list the same as slist, but
with all occurrences of s1 replaced by s2 and all occurrences of s2 replaced by s1.
> (swapper ’a ’d ’(a b c d))
(d b c a)
> (swapper ’a ’d ’(a d () c d))
(d a () c a)
> (swapper ’x ’y ’((x) y (z (x))))
((y) x (z (y)))
In scala, this is:
swapper("a", "d", List("a","b","c","d"))
swapper("a", "d", List("a","d",List(),"c","d"))
swapper("x", "y", List( List("x"), "y", List("z", List("x"))))
My scala version handles all versions save the final x.
def swapper(a: Any, b: Any, lst: List[Any]): List[Any] ={
def r(subList :List[Any], acc : List[Any]): List[Any] ={
def swap (x :Any, xs: List[Any]) =
if(x == a){
r(xs, acc :+ b)
} else if (x == b) {
r(xs, acc :+ a)
} else {
r(xs, acc :+ x)
}
subList match {
case Nil =>
acc
case List(x) :: xs =>
r(xs, r(List(x), List()) +: acc)
case x :: xs =>
swap(x,xs)
//case List(x) :: xs =>
}
}
r(lst, List())
}
Instinctively, I think this is because I have no swap on the section "case List(x) :: xs" but I'm still struggling to fix it.
More difficult, still, this case breaks the tail-call optimization. How can I do this and where can I go to learn more about the general solution?
You can use this foldRight with pattern match approach:
def swapper(a:Any, b:Any, list:List[Any]):List[Any] =
list.foldRight(List.empty[Any]) {
case (item, acc) if item==a => b::acc
case (item, acc) if item==b => a::acc
case (item:List[Any], acc) => swapper(a, b, item)::acc
case (item, acc) => item::acc
}
or even simplier (thanks to #marcospereira):
def swapper(a:Any, b:Any, list:List[Any]):List[Any] =
list.map {
case item if item==a => b
case item if item==b => a
case item:List[Any] => swapper(a, b, item)
case item => item
}
A simpler way to solve this is just use map:
def swapper[T](a: T, b: T, list: List[T]): List[T] = list.map { item =>
if (item == a) b
else if (item == b) a
else item
}
This seems to work.
def swapper[T](a: T, b: T, lst: List[_]): List[_] = {
val m = Map[T, T](a -> b, b -> a).withDefault(identity)
def swap(arg: List[_]): List[_] = arg.map{
case l: List[_] => swap(l)
case x: T => m(x)
}
swap(lst)
}
The List elements are inconsistent because it might be an element or it might be another List, so the type is List[Any], which is a sure sigh that someone needs to rethink this data representation.
Given e.g.:
List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
I'd like to get to:
List(List(5), List(2), List(3, 3, 3), List(5, 5), List(3, 3), List(2, 2, 2))
I would assume there is a simple List function that does this, but am unable to find it.
This is the trick that I normally use:
def split[T](list: List[T]) : List[List[T]] = list match {
case Nil => Nil
case h::t => val segment = list takeWhile {h ==}
segment :: split(list drop segment.length)
}
Actually... It's not, I usually abstract over the collection type and optimize with tail recursion as well, but wanted to keep the answer simple.
val xs = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
Here's another way.
(List(xs.take(1)) /: xs.tail)((l,r) =>
if (l.head.head==r) (r :: l.head) :: l.tail else List(r) :: l
).reverseMap(_.reverse)
Damn Rex Kerr, for writing the answer I'd go for. Since there are minor stylistic differences, here's my take:
list.tail.foldLeft(List(list take 1)) {
case (acc # (lst # hd :: _) :: tl, el) =>
if (el == hd) (el :: lst) :: tl
else (el :: Nil) :: acc
}
Since the elements are identical, I didn't bother reversing the sublists.
list.foldRight(List[List[Int]]()){
(e, l) => l match {
case (`e` :: xs) :: fs => (e :: e :: xs) :: fs
case _ => List(e) :: l
}
}
Or
list.zip(false :: list.sliding(2).collect{case List(a,b) => a == b}.toList)
.foldLeft(List[List[Int]]())((l,e) => if(e._2) (e._1 :: l.head) :: l.tail
else List(e._1) :: l ).reverse
[Edit]
//find the hidden way
//the beauty must be somewhere
//when we talk scala
def split(l: List[Int]): List[List[Int]] =
l.headOption.map{x => val (h,t)=l.span{x==}; h::split(t)}.getOrElse(Nil)
I have these implementations lying around from working on collections methods. In the end I checked in simpler implementations of inits and tails and left out cluster. Every new method no matter how simple ends up collecting a big tax which is hard to see from the outside. But here's the implementation I didn't use.
import generic._
import scala.reflect.ClassManifest
import mutable.ListBuffer
import annotation.tailrec
import annotation.unchecked.{ uncheckedVariance => uV }
def inits: List[Repr] = repSequence(x => (x, x.init), Nil)
def tails: List[Repr] = repSequence(x => (x, x.tail), Nil)
def cluster[A1 >: A : Equiv]: List[Repr] =
repSequence(x => x.span(y => implicitly[Equiv[A1]].equiv(y, x.head)))
private def repSequence(
f: Traversable[A #uV] => (Traversable[A #uV], Traversable[A #uV]),
extras: Traversable[A #uV]*): List[Repr] = {
def mkRepr(xs: Traversable[A #uV]): Repr = newBuilder ++= xs result
val bb = new ListBuffer[Repr]
#tailrec def loop(xs: Repr): List[Repr] = {
val seq = toCollection(xs)
if (seq.isEmpty)
return (bb ++= (extras map mkRepr)).result
val (hd, tl) = f(seq)
bb += mkRepr(hd)
loop(mkRepr(tl))
}
loop(self.repr)
}
[Edit: I forget other people won't know the internals. This code is written from inside of TraversableLike, so it wouldn't run out of the box.]
Here's a slightly cleaner one:
def groupConsequtive[A](list: List[A]): List[List[A]] = list match {
case head :: tail =>
val (t1, t2) = tail.span(_ == head)
(head :: t1) :: groupConsequtive(t2)
case _ => Nil
}
tail-recursive version
#tailrec
def groupConsequtive[A](list: List[A], acc: List[List[A]] = Nil): List[List[A]] = list match {
case head :: tail =>
val (t1, t2) = tail.span(_ == head)
groupConsequtive(t2, acc :+ (head :: t1))
case _ => acc
}
Here's a tail-recursive solution inspired by #Kevin Wright and #Landei:
#tailrec
def sliceEqual[A](s: Seq[A], acc: Seq[Seq[A]] = Seq()): Seq[Seq[A]] = {
s match {
case fst :: rest =>
val (l, r) = s.span(fst==)
sliceEqual(r, acc :+ l)
case Nil => acc
}
}
this could be simpler:
val input = List(5, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
input groupBy identity values