List 查找列表中的最后第二项,请解释此解决方案
有人能逐行评论这是在做什么吗 [A]是不是像c#中那样的泛型?我们会这样做吗 h似乎没有定义 我认为算法的主要部分是递归调用:List 查找列表中的最后第二项,请解释此解决方案,list,scala,recursion,functional-programming,pattern-matching,List,Scala,Recursion,Functional Programming,Pattern Matching,有人能逐行评论这是在做什么吗 [A]是不是像c#中那样的泛型?我们会这样做吗 h似乎没有定义 我认为算法的主要部分是递归调用: // But pattern matching also makes it easy. def penultimateRecursive[A](ls: List[A]): A = ls match { case h :: _ :: Nil => h case _ :: tail => penultimateRecursive(ta
// 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
是一个类型变量,意味着该函数是为任何类型A
定义的
h
由模式匹配绑定:第一个案例
声明,如果正好有两个元素,则调用第一个h
并返回它
似乎没有检查清单中的两项
有:h:::\u::Nil
表示“一个元素h
,后跟任何元素,后跟不再有元素。”Nil
不是元素,它是列表的结尾
然后拿第一件去拿最后的第二件
在两个元素列表中取第一个元素意味着取倒数第二个元素。如果列表中的元素少于或多于两个,则其他两种情况适用。理解模式匹配的关键是要认识到,
x::y
将只匹配一个列表,其中单个项x
,然后是列表的其余部分y
(可能只是Nil
,也可能是多个元素),这意味着“这里需要一些东西,但我们不会麻烦给它命名”。(并且匹配按顺序出现,列表以Nil
结尾)
您认为[A]
是泛型类型是正确的
因此,第一行:
case _ :: tail => penultimateRecursive(tail)
也就是说,如果我们的列表看起来(从概念上)像Node(h)->Node(无论什么)->Nil
,那么我们返回h
。这正是一个包含两个元素的列表,其中第一项已选中。请注意,Nil
不匹配列表的任意尾部;它只匹配列表项的末尾Nil
。这是因为Scala使用一条规则来区分这两个变量:小写变量被视为通配符,需要填入适当的值,而大写变量则被视为常数来匹配。(如果必须匹配小写名称,则可以使用反勾号将其环绕。)
好,现在假设它不是一个两元素列表。如果它不是空的,它将匹配
case h :: _ :: Nil => h
因此,如果我们没有两个元素的列表,我们就扔掉第一个元素,再试一次。最后,如果我们最终没有得到一个两元素列表,我们就可以
case _ :: tail => penultimateRecursive(tail)
我们完成了。(实际上,这也可能是
case Nil
,因为这是唯一与其他两个条目不匹配的可能性。)第一行表示,如果h后面紧跟着另一个元素和Nil指针(在列表末尾),则将返回任何列表元素h。h后面的实际元素并不重要,这就是为什么使用u指定有一个元素,但不关心它的值
如果第一种情况不匹配,那么第二种情况将调用递归,前提是列表有一个head元素和至少一个tail元素
最后,在只包含一个元素的列表中退出。再一次,您不必关心元素值的实际值。拉斯曼和雷克斯已经回答了您的问题,但有关“:”的更多详细信息,请参见第9章。
x::y
将匹配x
,然后是任何列表y
,即零个或更多元素。@larsmans-这就是我的意思,但是整个Nil
是一个不明显的项目(或者,根据你的观点,不正确)。我将修正我的措辞。您可以更清楚地说明,模式匹配中的小写标识符类似于val
声明,因为这些标识符是在该匹配的范围内创建的,并从匹配中提取赋值。请确定小写部分,并将其与比较的大写Nil
。在语言引用中哪里可以找到运算符::?列表是抽象的,有两个子类:::“和Nil。以下是前者的文档:
case _ => throw new NoSuchElementException