I want to remove duplicates from the list recursively using pattern matching with Scala
here is my input
val xs = List(1,2,3,4,6,3,2,7,9,4)
Tried code:
def removeDuplicates(xs : List[Int]) : List[Int] = xs match {
case Nil =>Nil
case x::ys => {
if(ys.contains(x)){
removeDuplicates(ys)
} else {
}
/// ???
}
}
I was stuck at the question mark, how to appened my result to the mutable list and return it.
Thank you.
You're close:
def removeDuplicates(xs : List[Int]) : List[Int] = xs match {
case Nil => Nil
case x::ys => if (ys.contains (x)) removeDuplicates (ys) else
x :: removeDuplicates (ys)
}
scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res143: List[Int] = List(1, 6, 3, 2, 7, 9, 4)
While this is a brief solution, it isn't tail recursive and therefore vulnerable for stackoverflows - whereas Jean Logearts solution solves the problem.
Here is an alternative solution with an inner function, tailrecursive too:
def removeDuplicates (xsOuter : List[Int]) : List[Int] = {
#annotation.tailrec
def removeDuplicates (xs: List[Int], collected: List[Int]) : List[Int] = xs match {
case Nil => collected
case x :: ys => if (collected.contains (x)) removeDuplicates (ys, collected) else
removeDuplicates (ys, x :: collected)
}
removeDuplicates (xsOuter, Nil)
}
scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res151: List[Int] = List(9, 7, 6, 4, 3, 2, 1)
with a bias to the first elements, but with the result reversed, which can be easily corrected by returning collected.reverse in the Nil case, if it is important.
The outer function serves the job to provide a simple, one-argument interface to the user, so he doesn't need to provide an empty List.
Note, that the solution is crying for a type annotation, since it doesn't depend at all on the List elements being of type Int:
scala> def removeDuplicates [A] (xsOuter : List[A]) : List[A] = {
|
| #annotation.tailrec
| def removeDuplicates (xs: List[A], collected: List[A]) : List[A] = xs match {
| case Nil => collected
| case x :: ys => if (collected.contains (x)) removeDuplicates (ys, collected) else
| removeDuplicates (ys, x :: collected)
| }
|
| removeDuplicates (xsOuter, Nil)
| }
removeDuplicates: [A](xsOuter: List[A])List[A]
scala> removeDuplicates (List (1,2,3,4,6,3,2,7,9,4))
res152: List[Int] = List(9, 7, 6, 4, 3, 2, 1)
You need to keep track of the current state: already seen elements using a set (for fast lookup), and the new list being constructed:
#tailrec
def removeDuplicatesRec(
remaining: List[Int],
seen: Set[Int],
acc: List[Int]
): List[Int] = remaining match {
case Nil => acc
case head :: tail =>
if (!seen.contains(head)) removeDuplicatesRec(tail, seen + head, acc :+ head)
else removeDuplicatesRec(tail, seen, acc)
}
def removeDuplicates(xs: List[Int]): List[Int] =
removeDuplicatesRec(xs, Set.empty, List.empty)
Here's a classic approach using an inner function and tail recursion. The tail recursion may not be necessary for small lists but it is easier for me to reason about.
def removeDuplicates(xs : List[Int]) : List[Int] = {
#scala.annotation.tailrec
def accumulator(xs: List[Int], acc: List[Int]):List[Int] = xs match {
case Nil => acc
case h::t if(!acc.contains(h)) => accumulator(t, h :: acc)
case h::t if(acc.contains(h)) => accumulator(t, acc)
}
accumulator(xs, List[Int]())
}
scala> removeDuplicates(List(1,2,3,4,6,3,2,7,9,4))
res16: List[Int] = List(9, 7, 6, 4, 3, 2, 1)
Of course, distinct is the preferred way to do this but this is a good exercise. distinct can be used to verify your solution though.
scala> List(1,2,3,4,6,3,2,7,9,4).distinct == removeDuplicates(List(1,2,3,4,6,3,2,7,9,4)).sorted
res21: Boolean = true
Related
The task is to remove all occurrences of element in a list using Tail Recursion and Match expression.
remove(List(2, 1, 4, 1, 3, 3, 1, 2), 1), should return : List(2, 4, 3, 3, 2)
This is a pseudocode, which works only for the first occurance. Can someone guide me how to do it so it would remove all occurances?
pseudocode
import scala.annotation.tailrec
object Test extends App{
def remove[A](l: List[A], el: A): List[A] = {
#tailrec
def helper(l: List[A], acc: List[A] = List[A]()): List[A] = {
l match {
case head :: tail if (head != el) => helper(tail, head::acc)
case head :: tail if (head == el) => (acc.reverse ::: tail)
case _ => acc
}
}
helper(l)
}
print(remove(List(2, 1, 4, 1, 3, 3, 1, 2), 1))
}
Your second pattern is not recursive, indeed its ending the recursion with the entire tail at the first match.
Further hint: you are building the accumulator in the reverse order, you can avoid the need to eventually reverse it with :+ to append in queue
def remove[A](l: List[A], el: A): List[A] = {
#tailrec
def helper(l: List[A], acc: List[A] = List[A]()): List[A] = {
l match {
case head +: tail => helper(tail, if(head != el) acc:+head else acc)
case _ => acc
}
}
helper(l)
}
print(remove(List(2, 1, 4, 1, 3, 3, 1, 2), 1))
as per jwvh comments this should be faster
import scala.annotation.tailrec
def remove[A](l: List[A], el: A): List[A] = {
#tailrec
def helper(l: List[A], acc: List[A] = List[A]()): List[A] = {
l match {
case head +: tail => helper(tail, if(head != el) head+:acc else acc)
case _ => acc.reverse
}
}
helper(l)
}
print(remove(List(2, 1, 4, 1, 3, 3, 1, 2), 1))
import scala.annotation.tailrec
object Zad3lab04 extends App{
def remove[A](l: List[A], el: A): List[A] = {
#tailrec
def helper(l: List[A], acc: List[A] = List[A]()): List[A] = {
l match {
case head :: tail if (head != el) => helper(tail, head::acc)
case head :: tail if (head == el) => helper(tail, acc)
case _ => acc
}
}
helper(l)
}
print(remove(List(2, 1, 4, 1, 3, 3, 1, 2), 1))
}
this works, prints list in diffrent order, if someone know why you could tell me. But it works so its fine.
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'm trying to recursively iterate through a list in Scala using pattern matching. I cannot use any list functions, or while/for loops. What I need to do is iterate through the list, and remove an element if it matches to be '4'. I'm new to Scala and I cannot find the answer in the textbook I have nor on google. Everyone else uses the filter method, or some other list method.
Here's what I tried to do (which is wrong)
def removeFours(lst: List[Int]): List[Int] = {
val newLst = lst
lst match {
case Nil => Nil
case a if a == 4 => newLst -= 0
case n => removeFours(newLst)
}
newLst
}
See if this works for you.
def removeFours(lst: List[Int], acc: List[Int] = List.empty): List[Int] = {
lst match {
case Nil => acc.reverse
case 4 :: t => removeFours( t, acc )
case h :: t => removeFours( t, h :: acc )
}
}
Usage:
scala> removeFours( List(3,7,4,9,2,4,1) )
res84: List[Int] = List(3, 7, 9, 2, 1)
Using an inner function and pattern matching to de-structure the list. If the head in the list is 4, then do not add it to the accumulator. If it is, append it to the accumulator.
def removeFours(lst: List[Int]): List[Int] = {
def loop(lst: List[Int], acc: List[Int]): List[Int] = lst match {
case Nil => acc
case h :: t =>
if (h == 4) {
loop(t, acc)
}else{
loop(t, acc :+ h)
}
}
loop(lst, List())
}
The preferred way to do this is with guards in the pattern match but the if else statement may look more familiar if you're just getting started with scala.
def removeFours(lst: List[Int]): List[Int] = {
def loop(lst: List[Int], acc: List[Int]): List[Int] = lst match {
case Nil => acc
case h :: t if (h == 4) => loop(t, acc)
case h :: t => loop(t, acc :+ h)
}
loop(lst, List())
}
I am not sure about the execution time. I am also new to scala but I am taking bollean approach to filter any list.
object Main extends App {
//fun that will remove 4
def rm_4(lst: List[Int]) : List[Int] = {
val a = lst.filter(kill_4)
a
}
// boolean fun for conditions
def kill_4(n: Int) : Boolean = {
if (n ==4) false
else true
}
println(rm_4(List(1,2,4,5,4))) // outpur List(1,2,5)
}
I want to write a function which will add an element n to a list n times for all elements in an input list.
For example:
L = List(2,4,1)
Output should be:
List(2,2,4,4,4,4,1)
I would like to do it with tail recursion. So far, I have written this:
def repeat(numbers: List[Int]): List[Int] = {
def repeat_acc(numbers: List[Int], acc: List[Int], number_acc: Int): List[Int] = {
if (numbers.length == 0)
return acc
else if (number_acc == 0)
repeat_acc(numbers.tail, acc, numbers.head)
else
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
}
repeat_acc(numbers, List(), 0)
}
The problem is that it leaves out the first element of the list. For this output will be:
(4, 4, 1, 1, 1, 1)
I know why it happens, but I cannot fix it. I have tried many other ways, but for me it seems that tail recursion do not work here. Some always goes wrong, and I get the wrong result.
Thanks for any advice.
I know you want to do a personalized tail recursive call, but I would recommend the following instead:
def repeat(numbers: List[Int]): List[Int] = {
numbers.flatMap(n => List.fill(n)(n))
}
The inner function takes the value n and repeats it n times in a list, and then this function is flat mapped onto the original list (a regular map would turn List(1,2,3) into List(List(1), List(2, 2), List(3, 3, 3)), so we use flat map). This has the benefit of 'doing it the Scala way' with built in collections functionality.
This problem gets a lot simpler if you add another parameter to your inner recursive method, representing the current number being added. You should also familiarize yourself with match statements, since they are really powerful in Scala and can help express exactly this type of logic. Nested if/else statements and early return statements are considered unidiomatic. Try:
def repeat(numbers: List[Int]) = {
def repeatAcc(acc: List[Int], curr: Int, rem: Int, numbers:List[Int]): List[Int] =
(numbers, rem) match {
case (Nil, 0) => acc
case (hd::tl, 0) => repeatAcc(acc, hd, hd, tl)
case (_, n) => repeatAcc(acc :+ curr, curr, n - 1, numbers)
}
repeatAcc(List.empty[Int], 0, 0, numbers)
}
You might also try to use some standard Scala methods like List.fill, which can be used in conjunction with the tail recursion as follows:
def repeat(numbers: List[Int]) = {
def repeatAcc(acc: List[Int], numbers:List[Int]): List[Int] = numbers match {
case hd::tl => repeatAcc(acc ++ List.fill(hd)(hd), tl)
case Nil => acc
}
repeatAcc(List.empty[Int], numbers)
}
Finally, I understand you're trying to learn about these core concepts, but it should be mentioned that this is really simple with Scala built ins:
(List.empty[Int] /: numbers) { case (soFar, next) => soFar ++ List.fill(next)(next) }
numbers.flatMap(x => List.fill(x)(x))
Try this, it works
import scala.annotation.tailrec
#tailrec
def f(l: List[Int], res: List[Int] = Nil): List[Int] = {
#tailrec
def g(n: Int, acc: List[Int]): List[Int] = {
if (n == 1) acc
else g(n - 1, acc :+ acc.head)
}
if (l == Nil) res else f(l.tail, res ++ g(l.head, List(l.head)))
}
scala> f(List(1,2,3))
res0: List[Int] = List(1, 2, 2, 3, 3, 3)
Ok, I find the solution. Looks bad, but works. I'm too tired to figure out something better.
Here is my code:
def repeat(numbers: List[Int]): List[Int] = {
def repeat_acc(numbers: List[Int], acc: List[Int], number_acc: Int): List[Int] = {
if (numbers.length == 1 && number_acc == 0)
return acc
else if (acc.length == 0)
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
else if (number_acc == 0 && numbers.tail != Nil ){
repeat_acc(numbers.tail, acc, (numbers.tail.head))
}
else
repeat_acc(numbers, acc :+ numbers.head, (number_acc-1))
}
repeat_acc(numbers, List(), numbers.head)
}
simple, just use fill + flatMap
val result = L.flatMap(x => List.fill(x)(x))
for recursive solution :
scala> def repeat(numbers: List[Int]): List[Int] = {
def run(nums:List[Int]):List[Int] ={
nums match {
case Nil => List.empty[Int]
case x::Nil => List.fill(x)(x)
case x::xs => List.fill(x)(x):::run(xs)
}}
run(numbers)
}
scala> repeat(List(2,4,1))
res1: List[Int] = List(2, 2, 4, 4, 4, 4, 1)
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