9
votes

I am trying to find the last element of a list in Scala using pattern matching. I tried following code

def last[A](list: List[A]):A = list match {
 case head :: Nil => head
 case head :: tail => last(tail)
 case _ => Nil
 }

The last case i.e. case _ => Nil is throwing error as type mismatch (found Nil.type require A)

I know this problem can be solved using other methods but using only pattern matching is there a way to solve this?

As the list is of generic type so I cannot replace Nil with default value of type A which can only be determined at runtime.

Removing this line: case _ => Nil is obviously working but with a warning that it will fail in case of Nil argument.

So, how can I handle Nil argument in this scenario?

3

3 Answers

42
votes

You can pattern match with :+.

def last[A](list: List[A]) = list match {
  case init :+ last => Some(last)
  case _ => None
}
4
votes

As you are not sure whether your list does contain any object you should handle such situation in general way. I'd suggest returning option type in your last method as follows:

def last[A](list: List[A]): Option[A] = list match {
    case head :: Nil => Some(head)
    case head :: tail => last(tail)
    case _ => None
}

Then in your code you can use monad-like interface to work with the result. You can either use map and process data in provided function, or use get method on option in case you are absolutely sure the list was not empty.

4
votes

use Option[T] to return the result, so if there is some element return Some(lastElement) otherwise Option.empty

Example,

  def last[A](list: List[A]): Option[A] = list match {
    case head :: Nil => Option(head)
    case head :: tail => last(tail)
    case _ => Option.empty
  }

  it("returns last element") {

    assert(last(List("apple")) == Some("apple"))
    assert(last(List("apple", "mango")) == Some("mango"))
    assert(last(List()) == Option.empty)
    assert(last(List()) == None)

  }

How to access the Option[T]?

last(List("In absentia", "deadwind")) match {
  case Some(lastValue) => println(s"Yayy there was lastValue = ${lastValue}") //prints Yayy there was lastValue = deadwind
  case None => println("Oops list was empty")
}

last(List()) match {
  case Some(lastValue) => println(s"Yayy there was lastValue = ${lastValue}")
  case None => println("Oops list was empty") //prints Oops list was empty
}

// or using map
last(List("In absentia", "deadwind")).map(lastValue => print(s"lastValue is ${lastValue}"))