Scala - Find duplicates in list using pattern matching and recursion - scala

I am trying to solve a beginner problem but can't reach the solution:
If any duplicates in list, return true, else false. Empty lists considered.
def duplicates(a: List[Int]): Boolean = {
case Nil => false
case x :: xs =>
if(xs.contains(x)) true else false
}
But this doesn't work. And it's not recursive. It's just something where I wanted to start but I'm stuck. Please kindly help and try to avoid non-beginner solutions if reasonable.

You need to call your function recursively. So if xs doesn't contain x, then call the function but with the remaining list.
def duplicates(a: List[Int]): Boolean = a match {
case Nil => false
case x :: xs =>
if(xs.contains(x)) true else duplicates(xs)
}

Related

Why is this function not tail recursive?

I'm writing a simple contains method for a list like structure. I want it to be optimized for tail recursion but can't figure out why the compiler is complaining.
The Cons case is tail recursive but not the repeat case even though they're making the same call on the same data structure. Maybe I'm not understanding tail recursion properly. If someone could clear this up I would a grateful.
final def contains[B >: A](target: B): Boolean = this match{
case Empty => false
case Cons( h, t ) => h == target || t.contains( target )
case Repeat( _, l ) => l.contains( target )
}
A tail-recursive function is defined as one whose last statement is either returning a plain value or calling itself, and that has to be the only recursive call.
First, your function doesn't have recursive calls, because you are not calling contains function again. But, you are calling the contains method of another instance.
That can be solved, by moving the logic outside the class.
However, there is another common problem.
This: h == target || t.contains( target ) is not a tail-recursive call, since the last operation is not the call to contains but the or (||) executed with its result.
Here is how you may refactor it.
def contains[A](list: MyList[A])(target: A): Boolean = {
#annotation.tailrec
def loop(remaining: MyList[A]): Boolean =
remaining match {
case Empty => false
case Cons(h, t) => if (h == target) true else loop(remaining = t)
case Repeat(_, l) => loop(remaining = l)
}
loop(remaining = list)
}
If you still want the method on your class, you can forward it to call this helper function passing this as the initial value.

Find max value in a list recursively in scala

I'm new to Scala, there is a better way to express this with the most basic knowledge possible?
def findMax(xs: List[Int]): Int = {
xs match {
case x :: tail => (if (tail.length==0) x else (if(x>findMax(tail)) x else (findMax(tail))))
}
}
Thee are two problems here. First, you call tail.length which is an operation of order O(N), so in the worst case this will cost you N*N steps where N is the length of the sequence. The second is that your function is not tail-recursive - you nest the findMax calls "from outside to inside".
The usual strategy to write the correct recursive function is
to think about each possible pattern case: here you have either the empty list Nil or the non-empty list head :: tail. This solves your first problem.
to carry along the temporary result (here the current guess of the maximum value) as another argument of the function. This solves your second problem.
This gives:
import scala.annotation.tailrec
#tailrec
def findMax(xs: List[Int], max: Int): Int = xs match {
case head :: tail => findMax(tail, if (head > max) head else max)
case Nil => max
}
val z = util.Random.shuffle(1 to 100 toList)
assert(findMax(z, Int.MinValue) == 100)
If you don't want to expose this additional argument, you can write an auxiliary inner function.
def findMax(xs: List[Int]): Int = {
#tailrec
def loop(ys: List[Int], max: Int): Int = ys match {
case head :: tail => loop(tail, if (head > max) head else max)
case Nil => max
}
loop(xs, Int.MinValue)
}
val z = util.Random.shuffle(1 to 100 toList)
assert(findMax(z) == 100)
For simplicity we return Int.MinValue if the list is empty. A better solution might be to throw an exception for this case.
The #tailrec annotation here is optional, it simply assures that we indeed defined a tail recursive function. This has the advantage that we cannot produce a stack overflow if the list is extremely long.
Any time you're reducing a collection to a single value, consider using one of the fold functions instead of explicit recursion.
List(3,7,1).fold(Int.MinValue)(Math.max)
// 7
Even I too am new to Scala (am into Haskell though!).
My attempt at this would be as below.
Note that I assume a non-empty list, since the max of an empty list does not make sense.
I first define an helper method which simply returns the max of 2 numbers.
def maxOf2 (x:Int, y:Int): Int = {
if (x >= y) x
else y
}
Armed with this simple function, we can build a recursive function to find the 'max' as below:
def findMax(xs: List[Int]): Int = {
if (xs.tail.isEmpty)
xs.head
else
maxOf2(xs.head, findMax(xs.tail))
}
I feel this is a pretty 'clear'(though not 'efficient') way to do it.
I wanted to make the concept of recursion obvious.
Hope this helps!
Elaborating on #fritz's answer. If you pass in an empty list, it will throw you a java.lang.UnsupportedOperationException: tail of empty list
So, keeping the algorithm intact, I made this adjustment:
def max(xs: List[Int]): Int = {
def maxOfTwo(x: Int, y: Int): Int = {
if (x >= y) x else y
}
if (xs.isEmpty) throw new UnsupportedOperationException("What man?")
else if (xs.size == 1) xs.head
else maxOfTwo(xs.head, max(xs.tail))
}
#fritz Thanks for the answer
Using pattern matching an recursion,
def top(xs: List[Int]): Int = xs match {
case Nil => sys.error("no max in empty list")
case x :: Nil => x
case x :: xs => math.max(x, top(xs))
}
Pattern matching is used to decompose the list into head and rest. A single element list is denoted with x :: Nil. We recurse on the rest of the list and compare for maximum on the head item of the list at each recursive stage. To make the cases exhaustive (to make a well-defined function) we consider also empty lists (Nil).
def maxl(xl: List[Int]): Int = {
if ( (xl.head > xl.tail.head) && (xl.tail.length >= 1) )
return xl.head
else
if(xl.tail.length == 1)
xl.tail.head
else
maxl(xl.tail)
}

What should max() return for empty lists?

Got java.util.NoSuchElementException: head of empty list so I tried to check for that. But now I get [info] - max of a few numbers *** FAILED ***
[info] 0 did not equal 7 (ListsSuite.scala:128)
def max(xs: List[Int]): Int = {
if xs.isEmpty 0 // What can I do?
else if (xs.head > max(xs.tail)) max(xs.tail)
else max(xs.tail)
}
edit:
The test case failed because my test was wrong.
For my classmates, a reminder of the Coursera honor code:
I will register for only one account. My answers to homework, quizzes
and exams will be my own work (except for assignments that explicitly
permit collaboration).
I will not make solutions to homework, quizzes
or exams available to anyone else. This includes both solutions
written by me, as well as any official solutions provided by the
course staff.
I will not engage in any other activities that will
dishonestly improve my results or dishonestly improve/hurt the
results of others.
In the general case, you can't return anything but None because an empty sequence in general has no meaningful default max value. That, however, is not necessarily the case all the time; for example you might want to find the maximum salary in a list of people, in which case it would make sense to say it's 0 if the list is empty; however, there is no trivial way to implement such default value logic generically (you'd have to use stuff like type classes and wrapped values); your best bet now is to simply use Option[Int]:
def max(xs: List[Int]): Option[Int] = xs match {
case Nil => None
case x :: Nil => Some(x)
case x :: xs => Some(x max max(xs))
}
Then, you can easily fall back to a default value at the call site:
val posOrNeg = List(-5, -2, 1, 4, 10)
max(posOrNeg) // => Some(10)
val posOrNeg = List.empty[Int]
max(posOrNeg) // => None
val onlyPos = List(1, 2, 3)
max(onlyPos).getOrElse(0) // => 3
val onlyPos = List.empty[Int]
max(onlyPos).getOrElse(0) // => 0
Bonus: Also, you can make your max work on any list of numeric values:
def max[T: Numeric](xs: List[T]): Option[T] = xs match {
case Nil => None
case x :: Nil => Some(x)
case x :: xs => Some(x max max(xs))
}
or in fact any suitable data structure made up of numeric values by using a type more general than List, but I'll leave that up to you.
But keep in mind: no matter which solution you opt for, always try to avoid try and exceptions in general — exceptions are not in the spirit of idiomatic functional programming (even though even some library functions use them occasionally for various reasons).
I'd go with Option.
def max(xs: List[Int]) =
if xs.isEmpty None
else if (xs.head > max(xs.tail)) Some( max(xs.tail) )
else Some( max(xs.tail))
The Option-Monad can either be Some( result ), meaning there is a result or None, meaning there is no result. If you wrap something in Some you say it's is a result and everything is fine.
As an alternative you solution you could wrap everything in a Try which would be the best because an empty list has no max and it's the right thing to get an error for that but now you can handle it in a functional way.
def max(xs: List[Int]) = Try( if (xs.head > max(xs.tail)) max(xs.tail) else xs.tail )
It doesn't make sense to define a max element for an empty collection, so you should either return a sentinel value, or throw an exception (e.g. IllegalArgumentException).
Also, you should make a few changes to your code (if you want to implement it yourself, and not use the built-in stuff):
def max(list: List[Int]): Option[Int] = {
list match {
// List has no elements, so we return None
case Nil => None
// Only one element, that is the maximum
case x :: Nil => Some(x)
// Compute max(list.tail).
// If defined, it will return the greater of list.tail and list.head
case head :: tail => max(tail).map(_ max head)
}
}

Use same variable multiple times within one pattern

I'd like to be able to use a single variable multiple times within one pattern, so that it will only match if the same value is present in all places, such as
list match {
case x :: x :: xs => // recurse
}
which would match List(1,1,2) but would not match List(1,2,1). But this does not compile with error: x is already defined as value x.
In researching this question, I found out that I can also include a guard in the case clause, so I can do
list match {
case x1 :: x2 :: xs if x1==x2 => // recurse
}
which seems to work the same way (it does, right?). This is good, but it wouldn't look as clean if I wanted the same value in many places, like
list match {
case x1::x2::x3::x4::xs if x1==x2 && x2==x3 && x3==x4 => // recurse
}
Is there any more elegant way I can do this?
A few notes: Yes, I am just learning scala, if that wasn't clear, so I'm not sure this is something I'd ever really want to do, but I'm just interested in what's possible. In that regard, I'm not really looking for a completely different solution, like takeWhile or filter or something, but more so am specifically interested in pattern matching.
Scala doesn't provide quite that much flexibility with its matches (which may be a good thing, as one has to be aware of errors arising from unintentional variable re-use).
If you have a large number of identical items, you might want to consider a nested match (but note that you won't fail out of the inner match to be completed later down the outer match, so you have to handle everything locally):
list match {
case x :: rest => rest match {
case `x` :: `x` :: `x` :: xs => println("Four of the same")
case _ => println("Well, nonempty at least")
}
case _ => println("Boring, there's nothing here!")
}
Note the backticks which mean "we've already got this variable, check against it, don't set it!".
Alternatively, if you have specialized functionality that you use repeatedly, you can create a custom matcher:
object FourOf {
def unapplySeq(xs: List[Int]): Option[(Int, List[Int])] = xs match {
case x :: y :: z :: a :: rest if x==y && y==z && z==a => Some((x,rest))
case _ => None
}
}
and then use it whenever you need that complicated pattern:
list match {
case FourOf(x,rest) => println("four of the same")
case x :: more => println("Nonempty")
case _ => println("Yawn")
}
Neither of these are quite as tidy and flexible as what you were apparently hoping for, but then again, I'm not sure flipping between assigning and testing the same variable in a match statement is a good way to write clear code anyway.
For many repeats you might use stable identifiers to do a comparison (instead of catching a value):
val x = list.head
list match {
case `x`::`x`::`x`::`x`::xs => ....
}
But note that this won't work on empty list (you just cannot get head of it).
I think Rex's answer rocks. I am a fan of unapplySeq. But here's a not-so-clever-and-maybe-wasteful alternative, if your main bother is just with the sequence of =='s in each guard.
So in the TMTOWTDI spirit:
def same[A](xs: A*) = xs forall (xs.head==)
// Then in your pattern match,
list match {
// case x1::x2::x3::x4::xs if x1==x2 && x2==x3 && x3==x4 => // recurse
case x1::x2::x3::x4::xs if same(x1,x2,x3,x4) => // recurse
}
I like Om's answer as well, so here's an adaptation:
list.headOption map (x => list match {
case `x`::`x`::`x`::`x`::xs => //...;
case _ => // ...
}) getOrElse {
// do what you'd have done for an empty list...
}

Tail recursion issue

We were experimenting with parallel collections in Scala and wanted to check whether the result was ordered. For that, I wrote a small function on the REPL to do that check on the very large List we were producing:
def isOrdered(l:List[Int]):Boolean = { l match {
case Nil => true
case x::Nil => true
case x::y::Nil => x>y
case x::y::tail => x>y & isOrdered(tail)
}
}
It fails with a stackOverflow (how appropriate for a question here!).
I was expecting it to be tail-optimized. What's wrong?
isOrdered is not the last call in your code, the & operator is. Try this instead:
#scala.annotation.tailrec def isOrdered(l:List[Int]):Boolean = { l match {
case Nil => true
case x::Nil => true
case x::y::Nil => x>y
case x::y::tail => if (x>y) isOrdered(tail) else false
}
}
Your algorithm is incorrect. Even with #Kim's improvement, isOrdered(List(4,3,5,4)) returns true.
Try this:
def isOrdered(l:List[Int]): Boolean = l match {
case Nil => true
case x :: Nil => true
case x :: y :: t => if (x <= y) isOrdered(l.tail) else false
}
(also updated so that signs are correct)
edit: my perferred layout would be this:
def isOrdered(list: List[Int]): Boolean = list match {
case Nil => true
case x :: Nil => true
case x :: xs => if (x > xs.head) false
else isOrdered(xs)
}
The quick way if performance isn't a problem would be
def isOrdered(l: List[Int]) = l == l.sorted
It can't be tail-optimized because you return this: 'x>y & isOrdered(tail)'. It means it will need to keep it on the stack.
Use the #tailrec annotation to force an error when you expect functions to be tail-recursive. It will also explain why it can't be.
I think the problem is that you're using the bitwise-and operator (&) in your last case. Since the runtime needs to know the value of the isOrdered call before it can evaluate the &, it can't tail-optimize the function. (That is, there is more code to run--the bitwise-and operation--after isOrdered is called.)
Using && or an if statement may help.