In scala, how can I use pattern match to match a list with specified length?

13,697

Solution 1

You don't have to match on Nil. What you could do instead is match on the rest.

1::Nil match {
   case 1::ts::rest => "Starts with 1. More than one element"
   case 1::Nil => "Starts with 1. Only one element"
}

With this code rest is than either a List or Nil and you make sure that the element has more than 1 element with the match on ts and then rest

Solution 2

In addition to the other answers, you can also use the apply method of the companion List object like so:

1::2::3::Nil match {
  case List(1, _, _*) => "Starts with 1. More than one element"
  case List(1) => "Starts with 1. Only one element"
}

Solution 3

By rearranging the cases and adding a third case for completeness (exhaustive matching), this captures the intended semantics,

1 :: 2 :: 3 :: Nil match {
  case 1 :: Nil => "Just one"
  case 1 :: xs => "One and more"
  case _ => "Unknown"
}

Note the second case extracts the first element and the rest which cannot be an empty list (Nil) since this possibility did not match in the first case: here, xs includes at least one more non empty list; the last case covers empty lists.

Solution 4

To generalize this problem, you might write your own extractor. To match on lists of an arbitrary length with a given first element, you could:

object HeadWithLength {
    def unapply[A](list: Seq[A]): Option[(Option[A], Int)] = 
        Some(list.headOption -> list.length)
}

And then you can match:

List(1, 3, 4) match {
    case HeadWithLength(Some(head), length) => println(s"Head is $head and length is $length") 
}
Share:
13,697
Hanfei Sun
Author by

Hanfei Sun

Just another stackoverflow user cs.cmu.edu/~hanfeis

Updated on June 05, 2022

Comments

  • Hanfei Sun
    Hanfei Sun almost 2 years

    My codes looks like this:

    1::2::Nil match {
      case 1::ts::Nil => "Starts with 1. More than one element"
      case 1::Nil => "Starts with 1. Only one element"
    }
    

    I tried to use 1::ts::Nil to match the List who starts with 1 and whose length is greater than 1. It workes well for 2-element list, however, this pattern doesn't work for 3-element list, for example:

    1::2::3::Nil match {
      case 1::ts::Nil => "Starts with 1. More than one element"
      case 1::Nil => "Starts with 1. Only one element"
    }
    

    This won't work..Does anyone have ideas about this?