在 Scala 中,如何使用模式匹配来匹配具有指定长度的列表?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28644861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 06:55:46  来源:igfitidea点击:

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

listscalafunctional-programmingpattern-matching

提问by Hanfei Sun

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::Nilto match the List who starts with 1and 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::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"
}

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

这行不通..有人对此有想法吗?

回答by matthias

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

你不必匹配 Nil。你可以做的是匹配其余的。

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

使用此代码,rest 不是 List 或 Nil,并且您确保该元素具有超过 1 个与 ts 匹配的元素,然后休息

回答by elm

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, xsincludes at least one more non empty list; the last case covers empty lists.

请注意,第二种情况提取第一个元素,其余元素不能是空列表 ( Nil),因为这种可能性在第一种情况下不匹配:这里,xs至少包括一个非空列表;最后一种情况涵盖空列表。

回答by has981

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

除了其他答案之外,您还可以像这样使用伴随 List 对象的 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"
}

回答by Ben Reich

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") 
}

回答by mohit

tsis matching one element of the list. In your first case, tsmatches 2 i.e. 1in the list matches with 1in the pattern statement, tsmatches with 2in the list and Nilin the list matches with Nilin the pattern statement and you don't get any MatchError

ts匹配列表中的一个元素。在您的第一种情况下,ts匹配 2 即1列表中的匹配与1模式语句中的ts匹配,2列表Nil中的匹配和列表中的匹配与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

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.

在您的第二种情况下,您试图将 ts 与 2 和 3 匹配,这是不可能的,因此会引发 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

如果模式匹配中的案例可以是您实际用例的任何条件