列表的第二个元素

时间:2018-04-09 08:53:41

标签: scala list

从Scala中的Book编程我得到以下代码:

val second: List[ Int] => Int = { case x :: y :: _ => y }
//warning: match may not be exhaustive.

它声明如果列表不为空或为零,则此函数将返回整数列表的第二个元素。 Stil这部分对我来说有点尴尬:

case x :: y :: _ 

这如何有效地工作?这是否会计算出至少包含2个元素的列表,而不是返回第二个?如果是这样,有人还能解释语法吗?我理解::在右操作数上调用::。所以它可以写成

(_.::(y)).::(X)

仍然我不知道为什么会返回2

val second: List[ Int] => Int = { case x :: y :: _ => y }
var x = List(1,2)
second(x) //returns 2 

4 个答案:

答案 0 :(得分:1)

second属于函数类型,需要List[Int]并返回Int

如果列表中有第一个元素(" x"),第二个元素(" y"),以及下一个元素(我们不关心它) ,我们只返回元素" y" (这是列表的第二个元素)。

在任何其他情况下,未定义该功能。你可以查看:

scala> val second: PartialFunction[List[Int], Int] = {
     |     case x :: y :: _ => y
     |   }
second: PartialFunction[List[Int],Int] = <function1>

scala> second.isDefinedAt(List(1,2,3))
res18: Boolean = true

scala> second.isDefinedAt(List(1,2))
res19: Boolean = true

scala> second.isDefinedAt(List(0))
res20: Boolean = false

答案 1 :(得分:1)

在REPL中,您可以输入:

scala> val list = "a" :: "b" :: Nil 
list: List[String] = List(a, b)

从右到左阅读,意味着以List(Nil)结束,在字符串“b”之前和此List(“b”:: Nil)前面添加字符串a,a ::( “b”:: Nil)但你不需要parens,所以它可以写成“a”::“b”:: Nil。

在模式匹配中,您会经常看到:

... list match {
  case Nil => // ... 
  case x :: xs => // ...
}

区分空列表和非空,其中xs可能是列表的其余部分,但也匹配Nil,如果整个列表是(“b”:: Nil),例如,则x =“b”和xs =无。

但是如果list =“a”::“b”:: Nil,那么x =“a”和xs =(b :: Nil)。

在你的例子中,解构只是一步,而不是像xs这样的名字,使用了小丑符号_,表示该名称可能没有被使用而且没有发挥作用。

答案 2 :(得分:1)

首先。当您考虑模式匹配时,您应该考虑匹配结构。

case语句的第一部分描述了一个结构。该结构可以描述对于导出结果有用的一个或多个事物(变量)。

在您的示例中,您有兴趣派生列表的第二个元素。在Scala中构建列表的简写是使用::方法(也称为 cons )。 ::也可用于描述case语句中的结构。 目前,您不应该考虑在:: 的第一部分评估case方法。可能是你说_.::(y).::(x)评价的原因。 :: cons运算符帮助我们根据元素描述列表的结构。在这种情况下,第一个元素(x),第二个元素(y)和其余元素(_通配符)。我们感兴趣的是一个结构,它是一个至少有2个元素的列表,第三个可以是任何东西 - 一个Nil表示列表的结尾或另一个元素 - 因此是通配符。

case语句的第二部分,使用第二个元素派生结果(y)。

更多关于列表和消费

Scala中的列表类似于LinkedList。您知道名为head的第一个元素以及列表其余部分的开头。遍历链接列表时,如果列表的其余部分为Nil,则停止。这个:: cons运算符可以帮助我们可视化链表的结构。虽然Scala编译实际上会调用::方法,正如您所描述的那样从右到左进行评估_.::(y).::(x)

顺便说一句,你可能已经注意到Scala编译器可能会抱怨你的匹配并不详尽。这意味着此second方法适用于任何大小的列表。因为没有任何case语句来描述具有零个或一个元素的列表。此外,如前面答案的评论中所述,如果您对第一个元素不感兴趣,可以将其描述为通配符_

case _ :: y :: _ => y

我希望这有帮助。

答案 3 :(得分:0)

如果你在scala中看到列表的结构为<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <body> <div class="container"> <p id="paragraph">word is sold</p> </div> </body>,则第一个元素被视为head,所有剩余的元素被视为tail(Nil将是tail的最后一个元素)。每当你执行x :: y :: _时,x将匹配列表的头部,剩下的将是尾部,y将匹配下一个列表的头部(第一个列表的尾部)

例如:

head::tail

您可以通过不同的方式查看此列表:

val l = List(1,2,3,4,5)

等等

所以尝试匹配模式。在你的问题中,y将给出第二个元素