Scala - Pattern Matching with Lists



Lists in Scala can be used in pattern matching to decompose their elements and handle them expressively. Extending lists with the Matchable trait ensures safe pattern matching.

Syntax

The syntax of list matching is -

list match {
  // pattern matching logic
  case List(...) =>
  // default case
  case _ =>
}

Basic List Patterns

You can match basic lists by their structure and contents. So, you can handle specific list shapes and values.

Example

Try following example for basic list patterns -

object Demo {
  def main(args: Array[String]): Unit = {
    val intList: List[Matchable] = List(1, 2, 3)
    val stringList: List[Matchable] = List("Scala", "Java")
    val mixedList: List[Matchable] = List(1, "Scala", 3.14)

    println(matchList(intList))
    println(matchList(stringList))
    println(matchList(mixedList))
  }

  def matchList(lst: List[Matchable]): String = lst match {
    case List(1, 2, 3) => "List of Int: [1, 2, 3]"
    case List("Scala", "Java") => "List of Strings: [Scala, Java]"
    case List(_, "Scala", _) => "List with Scala in the middle"
    case _ => "Unknown list"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

List of Int: [1, 2, 3]
List of Strings: [Scala, Java]
List with Scala in the middle

Matching Lists with Fixed Size

You can match lists of a specific size to ensure they conform to expected lengths. This is used for validating list structures.

Syntax

The syntax is as follows -

list match {
  // logic for list with exactly 2 elements
  case List(a, b) =>
  // logic for list with exactly 5 elements
  case List(a, b, c, d, e) =>
  // default case
  case _ =>
}

Example

Try following example for matching lists with fixed size -

object Demo {
  def main(args: Array[String]): Unit = {
    val smallList: List[Matchable] = List(1, 2)
    val largeList: List[Matchable] = List(1, 2, 3, 4, 5)

    println(matchFixedSizeList(smallList))
    println(matchFixedSizeList(largeList))
  }

  def matchFixedSizeList(lst: List[Matchable]): String = lst match {
    case List(_, _) => "List with exactly 2 elements"
    case List(_, _, _, _, _) => "List with exactly 5 elements"
    case _ => "List with unknown size"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

List with exactly 2 elements
List with exactly 5 elements

Pattern Matching with List Elements

You can pattern match specific elements within lists to extract and process values.

Syntax

The syntax is as follows -

list match {
  // logic for lists with three elements
  case List(first, second, third) => 
  // default case
  case _ => 
}

Example

Try following example for matching pattern of elements of list -

object Demo {
  def main(args: Array[String]): Unit = {
    val numbers: List[Matchable] = List(10, 20, 30)

    println(matchListElements(numbers))
  }

  def matchListElements(lst: List[Matchable]): String = lst match {
    case List(first, second, third) => s"First: $first, Second: $second, Third: $third"
    case _ => "List does not have exactly 3 elements"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

First: 10, Second: 20, Third: 30

Matching Lists of Different Types

You can handle lists containing different types by pattern matching on the type of each element.

Syntax

The syntax is as follows -

list match {
  // logic for lists with specified types
  case List(a: Int, b: String, c: Double) => 
  // default case
  case _ => 
}

Example

Try following example for matching lists of different types -

object Demo {
   def main(args: Array[String]): Unit = {
      val mixedList: List[Matchable] = List(1, "Scala", 3.14)

      println(matchDifferentTypesList(mixedList))
   }

   def matchDifferentTypesList(lst: List[Matchable]): String = lst match {
      case List(i: Int, s: String, d: Double) => s"Int: $i, String: $s, Double: $d"
      case _ => "List does not match expected types"
   }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Int: 1, String: Scala, Double: 3.14

Handling Nested Lists

You can match nested lists to handle more complex data structures. You can list of lists as follows as below -

Syntax

Here is the syntax to handle pattern matching with nested lists -

list match {
  // logic for nested lists
  case List(List(...), List(...)) => 
  // default case
  case _ => 
}

Example

Try following example for handling nested lists -

object Demo {
  def main(args: Array[String]): Unit = {
    val nestedList: List[List[Matchable]] = List(List(1, 2), List(3, 4))

    println(matchNestedList(nestedList))
  }

  def matchNestedList(lst: List[List[Matchable]]): String = lst match {
    case List(List(1, 2), List(3, 4)) => "Nested list: [[1, 2], [3, 4]]"
    case _ => "Unknown nested list"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Nested list: [[1, 2], [3, 4]]

Guards in List Patterns

You can use guards in pattern matching to add additional conditions.

Syntax

The syntax is as follows -

list match {
  // logic with guard condition
  case List(a, b, c) if condition => 
  // default case
  case _ => 
}

Example

Try following example of guards in list patterns -

object Demo {
  def main(args: Array[String]): Unit = {
    val numbers: List[Matchable] = List(10, 20, 30)

    println(matchWithGuards(numbers))
  }

  def matchWithGuards(lst: List[Matchable]): String = lst match {
    case List(first: Int, second, third) if first > 5 => s"First is greater than 5: $first"
    case _ => "List does not match guard condition"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

First is greater than 5: 10

Combining List Patterns with Other Patterns

List patterns can be combined with other patterns to handle more complex matching.

Syntax

The syntax is as follows −

(list, otherPattern) match {
  // logic for combined patterns
  case (List(...), ...) => 
  // default case
  case _ => 
}

Example

Try following example for combining list patterns with other patterns -

object Demo {
  def main(args: Array[String]): Unit = {
    val mixedList: List[Matchable] = List(Person("Alice", 25), Dog("Rex"))

    println(matchCombinedPatterns(mixedList))
  }

  case class Person(name: String, age: Int) extends Matchable
  case class Dog(name: String) extends Matchable

  def matchCombinedPatterns(lst: List[Matchable]): String = lst match {
    case List(Person(name, age), Dog(dogName)) => s"Person: $name, Dog: $dogName"
    case _ => "Unknown pattern"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

Person: Alice, Dog: Rex

Advanced List Patterns

You can use advanced patterns to match complex and variable-length lists.

Syntax

The syntax is as follows -

list match {
  // logic for list starting with a specific element
  case List(first, _*) => 
  // logic for list with specific second element
  case List(_, second, _*) => 
  // default case
  case _ => 
}

Example

Try following example of advanced list patterns -

object Demo {
  def main(args: Array[String]): Unit = {
    val advancedList: List[Matchable] = List(1, 2, 3, 4, 5)

    println(matchAdvancedPatterns(advancedList))
  }

  def matchAdvancedPatterns(lst: List[Matchable]): String = lst match {
    case List(1, _*) => "List starts with 1"
    case List(_, 2, _*) => "List has 2 as the second element"
    case _ => "Unknown pattern"
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

List starts with 1

Pattern Matching with Lists Summary

  • You can match Lists by structure and contents.
  • You can match lists of specific sizes to conform to expected lengths.
  • You can also match specific elements within lists to extract and process values.
  • Lists containing different types can be handled by pattern matching on the type of each element.
  • You can match nested lists and lists with guards in pattern matching to add more conditions.
  • You can combine list patterns with other patterns to handle more complex matching.
  • You can also use advanced patterns to match complex and variable-length lists.
Advertisements