在Scala列表中查找倒数第二个元素

时间:2017-12-31 08:05:21

标签: scala

我是Scala的新手,我正在学习关于集合的模式匹配,以便编写一个简单的逻辑来查找最后一个元素。这是我的第一次尝试:

@scala.concurrent.tailrec
def penultimate[A](elems: List[A]) = elems match {
  case Nil => None 
  case first :: second :: Nil => Some(first)
  case head :: tail => penultimate(tail)
} 

这够好吗?我读到了关于尾递归的信息,并且我的方法是尾递归的!

但是,对于以下情况并且我期望Some(1):

,它失败了
penultimate[Int](List(1)) // This should give me Some(1)

我还能做些什么吗?我可以使用Scala集合库中的反向方法,并使其成为一个单行,但我想远离使用它。

有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

如果您修复了这两个简单的编译错误,您的代码似乎可以正常工作。编写此方法的另一种方法是:

def penultimate[A](elems: List[A]) = elems match {
  case _ :+ elem :+ _ => Some(elem)
  case elem +: Nil => Some(elem) // strange extra requirement
  case _ => None
} 

:+Seq解构为(1)除最后一个元素之外的所有元素的列表,以及(2)最后一个元素。与::或更为一般的+:相似但反向。我本来可以写case init :+ elem :+ last,但我不想给我不打算使用的模式部分命名。

答案 1 :(得分:0)

倒数第二位的要求是,列表中至少应包含2个元素。因此,在上面的“ penultimateInt”中应该抛出异常。

def penultimate[A](elems: List[A]) = {
  val result = getSecondLast(elems)
  if(result.isDefined) result.get else throw new Exception("list doesn't have 
    enough elementss")
}

@tailrec
private def getSecondLast[A](list: List[A], secondLast: Option[A] = None): 
  Option[A] = {
  list match {
    case secondLast :: _ :: Nil => Some(secondLast)
    case _ :: tail => getSecondLast(tail, secondLast)
    case _ => None
  }
}

以上是递归方法。 使用可用方法的其他方式是:

  1. list.init.last
  2. list.takeRight(n).head