在 Scala 中,如何使用模式匹配来匹配指定长度的列表?
In scala, how can I use pattern match to match a list with specified length?
我的代码如下所示:
1::2::Nil match {
case 1::ts::Nil => "Starts with 1. More than one element"
case 1::Nil => "Starts with 1. Only one element"
}
我尝试使用1::ts::Nil
来匹配以1
开头且长度大于1的列表。它适用于2元素列表,但是,这种模式并不适用为 3-element list
工作,例如:
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"
}
这行不通..有人对此有想法吗?
您不必匹配 Nil。你可以做的是在其余部分进行匹配。
1::Nil match {
case 1::ts::rest => "Starts with 1. More than one element"
case 1::Nil => "Starts with 1. Only one element"
}
使用此代码,rest 不是 List 或 Nil,并且您确保该元素有超过 1 个元素与 ts 匹配,然后是 rest
ts
匹配列表中的一个元素。在您的第一种情况下,ts
匹配 2,即列表中的 1
与模式语句中的 1
匹配,ts
与列表中的 2
匹配,并且 [列表中的 =16=] 与模式语句中的 Nil
匹配,您不会得到任何 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</pre>
在你的第二种情况下,你试图将 ts 与 2 和 3 进行匹配,这是不可能的,因此它会抛出 MatchError。
如果你想根据大小进行模式匹配,你可以这样做
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</pre>
If case in the pattern match can be any condition for your real use case
通过重新排列案例并添加第三个案例以确保完整性(穷举匹配),这捕获了预期的语义,
1 :: 2 :: 3 :: Nil match {
case 1 :: Nil => "Just one"
case 1 :: xs => "One and more"
case _ => "Unknown"
}
注意第二种情况提取第一个元素,其余元素不能为空列表 (Nil
),因为这种可能性在第一种情况下不匹配:这里,xs
至少包括又一个非空列表;最后一个案例涵盖了空列表。
要概括这个问题,您可以编写自己的提取器。要将任意长度的列表与给定的第一个元素匹配,您可以:
object HeadWithLength {
def unapply[A](list: Seq[A]): Option[(Option[A], Int)] =
Some(list.headOption -> list.length)
}
然后你可以匹配:
List(1, 3, 4) match {
case HeadWithLength(Some(head), length) => println(s"Head is $head and length is $length")
}
除了其他答案,您还可以像这样使用伴随列表对象的 apply 方法:
1::2::3::Nil match {
case List(1, _, _*) => "Starts with 1. More than one element"
case List(1) => "Starts with 1. Only one element"
}
我的代码如下所示:
1::2::Nil match {
case 1::ts::Nil => "Starts with 1. More than one element"
case 1::Nil => "Starts with 1. Only one element"
}
我尝试使用1::ts::Nil
来匹配以1
开头且长度大于1的列表。它适用于2元素列表,但是,这种模式并不适用为 3-element list
工作,例如:
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"
}
这行不通..有人对此有想法吗?
您不必匹配 Nil。你可以做的是在其余部分进行匹配。
1::Nil match {
case 1::ts::rest => "Starts with 1. More than one element"
case 1::Nil => "Starts with 1. Only one element"
}
使用此代码,rest 不是 List 或 Nil,并且您确保该元素有超过 1 个元素与 ts 匹配,然后是 rest
ts
匹配列表中的一个元素。在您的第一种情况下,ts
匹配 2,即列表中的 1
与模式语句中的 1
匹配,ts
与列表中的 2
匹配,并且 [列表中的 =16=] 与模式语句中的 Nil
匹配,您不会得到任何 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</pre>
在你的第二种情况下,你试图将 ts 与 2 和 3 进行匹配,这是不可能的,因此它会抛出 MatchError。
如果你想根据大小进行模式匹配,你可以这样做
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</pre>
If case in the pattern match can be any condition for your real use case
通过重新排列案例并添加第三个案例以确保完整性(穷举匹配),这捕获了预期的语义,
1 :: 2 :: 3 :: Nil match {
case 1 :: Nil => "Just one"
case 1 :: xs => "One and more"
case _ => "Unknown"
}
注意第二种情况提取第一个元素,其余元素不能为空列表 (Nil
),因为这种可能性在第一种情况下不匹配:这里,xs
至少包括又一个非空列表;最后一个案例涵盖了空列表。
要概括这个问题,您可以编写自己的提取器。要将任意长度的列表与给定的第一个元素匹配,您可以:
object HeadWithLength {
def unapply[A](list: Seq[A]): Option[(Option[A], Int)] =
Some(list.headOption -> list.length)
}
然后你可以匹配:
List(1, 3, 4) match {
case HeadWithLength(Some(head), length) => println(s"Head is $head and length is $length")
}
除了其他答案,您还可以像这样使用伴随列表对象的 apply 方法:
1::2::3::Nil match {
case List(1, _, _*) => "Starts with 1. More than one element"
case List(1) => "Starts with 1. Only one element"
}