How to use Lists in Scala match expressions

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 3.15, “How to use Lists in Scala match expressions.”

Problem

You know that a Scala List data structure is a little different than other collection data structures. It’s built from “cons” cells and ends in a Nil element. You want to use this to your advantage when working with a match expression, such as when writing a recursive function.

Solution

You can create a List like this:

val x = List(1, 2, 3)

or like this, using cons cells and a Nil element:

val y = 1 :: 2 :: 3 :: Nil

When writing a recursive algorithm, you can take advantage of the fact that the last element in a List is a Nil object. For instance, in the following listToString method, if the current element is not Nil, the method is called recursively with the remainder of the List, but if the current element is Nil, the recursive calls are stopped and an empty String is returned, at which point the recursive calls unwind:

def listToString(list: List[String]): String = list match {
    case s :: rest => s + " " + listToString(rest)
    case Nil => ""
}

Running this example in the REPL yields the following result:

scala> val fruits = "Apples" :: "Bananas" :: "Oranges" :: Nil
fruits: List[java.lang.String] = List(Apples, Bananas, Oranges)

scala> listToString(fruits)
res0: String = "Apples Bananas Oranges "

The same approach of (a) handling the Nil condition and (b) handling the remainder of the List can be used when dealing with a List of other types:

def sum(list: List[Int]): Int = list match {
    case Nil => 0
    case n :: rest => n + sum(rest)
}

def multiply(list: List[Int]): Int = list match {
    case Nil => 1
    case n :: rest => n * multiply(rest)
}

These methods are demonstrated in the REPL:

scala> val nums = List(1,2,3,4,5)
nums: List[Int] = List(1, 2, 3, 4, 5)

scala> sum(nums)
res0: Int = 15

scala> multiply(nums)
res1: Int = 120

Discussion

When using this recipe, be sure to handle the Nil case, or you’ll get the following error in the REPL:

warning: match is not exhaustive!

In the real world (outside the REPL), you’ll get a MatchError:

Exception in thread "main" scala.MatchError: List()
(of class scala.collection.immutable.Nil$)

See Also

  • Recipe 3.11, “Using Pattern Matching in Match Expressions”, for more examples of using a match expression with multiple types