问题
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?
回答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
回答2:
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.
回答3:
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"
}
回答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")
}
回答5:
ts
is matching one element of the list. In your first case, ts
matches 2 i.e. 1
in the list matches with 1
in the pattern statement, ts
matches with 2
in the list and Nil
in the list matches with Nil
in the pattern statement and you don't get any MatchError
1 :: 2 :: Nil match {
case 1 :: ts :: Nil => println("ts is "+ts)
"Starts with 1. More than one element"
case 1 :: Nil => "Starts with 1. Only one element"
} //> ts is 2
//| res1: String = Starts with 1. More than one element
In your second case, you are trying to match ts with both 2 and 3 which is not possible and hence it throws a MatchError.
If you want to do a pattern match based on size, you can do
1 :: 2 :: 3 :: Nil match {
case 1 :: tail if tail.size > 1 => "Starts with 1. More than one element"
case 1 :: Nil => "Starts with 1. Only one element"
} //> res0: String = Starts with 1. More than one element
If case in the pattern match can be any condition for your real use case
来源:https://stackoverflow.com/questions/28644861/in-scala-how-can-i-use-pattern-match-to-match-a-list-with-specified-length