In scala, how can I use pattern match to match a list with specified length?
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")
}
Comments
-
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 with1
and whose length is greater than 1. It workes well for 2-element list, however, this pattern doesn't work for3-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?