找到列表中的第二个最后一项,请解释此解决方案

时间:2011-06-30 19:37:17

标签: list scala recursion functional-programming pattern-matching

// But pattern matching also makes it easy.
  def penultimateRecursive[A](ls: List[A]): A = ls match {
    case h :: _ :: Nil => h
    case _ :: tail     => penultimateRecursive(tail)
    case _             => throw new NoSuchElementException
  }

有人可以逐行评论这是做什么的吗?

[A]是否像c#一样通用,我们会这样做吗?

h似乎没有被定义?

我认为算法的主要部分是递归调用:

case _ :: tail     => penultimateRecursive(tail)

似乎没有检查列表中的2个项目,然后拿第1个项目获得第2个项目,很困惑!

4 个答案:

答案 0 :(得分:10)

理解模式匹配的关键是要意识到x :: y匹配列表,其中包含单个项x,后跟列表的其余部分{{1 (可能只是y,或者可能是很多元素),Nil表示“这里需要有东西,但我们不会打扰它”。 (并且匹配按顺序发生,并且列出以_结尾。)

你是正确的Nil是通用类型。

所以,第一行:

[A]

说,如果我们的列表看起来像(概念上)case h :: _ :: Nil => h ,那么我们返回Node(h) -> Node(whatever) -> Nil。这正是一个包含所选第一个项目的双元素列表。请注意,h 匹配列表的任意尾部;它仅匹配列表末尾项Nil。这是因为Scala用来区分这两者的规则:小写变量被视为要填充适当值的通配符,而大写变量被视为要匹配的常量。 (如果必须匹配小写名称,则可以通过反引号将其包围。)

好的,现在假设它不是一个双元素列表。然后,如果它不是空的,它将匹配

Nil

所以如果我们没有两个元素的列表,我们会扔掉第一个项目并再试一次。最后,如果我们以某种方式永远不会得到一个双元素列表,我们就会进入

case _ :: tail => penultimateRecursive(tail)

我们已经完成了。 (实际上,这也可能是case _ => throw new NoSuchElementException ,因为这是唯一与其他两个条目不匹配的可能性。)

答案 1 :(得分:4)

A是一个类型变量,意味着该函数通常为任何类型A定义。

h受模式匹配约束:第一个case个状态,如果只有两个元素,则调用第一个h并返回它。

  

似乎没有检查列表中的2个项目

有:h :: _ :: Nil表示“元素h,后跟任何元素,后面没有更多元素。” Nil不是元素,它是列表的末尾。

  

然后拿第一项获得第二名

取两个元素列表中的第一个 意味着取倒数第二个。如果列表中的元素少于或少于两个,则另外两种情况适用。

答案 2 :(得分:3)

larsmans和Rex已经涵盖了您的问题,但有关'::'http://www.scala-lang.org/docu/files/ScalaByExample.pdf

的详细信息,请参阅第9章。

答案 3 :(得分:1)

第一行表示如果h后跟另一个和Nil指针(在列表的末尾),则将返回任何列表元素h。 h后面的实际元素并不重要,这就是为什么你使用_来指定有一个元素,但你不关心它的值。

如果第一种情况不匹配,如果列表具有头元素和至少一个元素的尾部,则第二种情况将调用递归。

最后,你在只包含一个元素的列表上拯救。再一次,您不必关心元素值的实际值。