【问题标题】:Finding the Penultimate Element in Scala List在 Scala 列表中查找倒数第二个元素
【发布时间】:2020-12-22 11:58:26
【问题描述】:

我是 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 集合库中的 reverse 方法并使其成为单行,但我不想使用它。

有更好的方法吗?

【问题讨论】:

  • 你说的不对。首先:您的代码无法编译。第二:修复编译错误时penultimate(List(1))返回None
  • 很抱歉造成混乱!我已经编辑了我的帖子!
  • 现在我很困惑。为什么你会期待Some(1)
  • 如果列表只包含一个元素,我想返回那个元素!这对我来说只是一些实验。当列表中只有一个元素时,这并不是一个硬性规定。我喜欢你的回答非常简洁,但是对于像我这样从 Scala 开始的人来说,理解通配符的用法可能不是那么简单!

标签: scala


【解决方案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,但我不想为我不打算使用的模式部分命名。

【讨论】:

    【解决方案2】:

    Penultimate 的首先要求是列表中至少应包含 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-08
      • 2017-02-11
      • 1970-01-01
      • 1970-01-01
      • 2011-09-19
      • 1970-01-01
      • 2017-10-27
      • 2021-05-19
      相关资源
      最近更新 更多