给定序列中的元素,如何获取前一个元素?

sam*_*m-w 6 scala scala-collections

假设我有一个Scala列表List("apple", "orange", "banana", "chinese gooseberry")*.我想搜索此列表并返回列表中与我已有项目相关的上一项.

例如:getPrevious(fruit: String, fruits: List[String]): Option[String]应该返回

  • Some("apple")如果我把它称为fruitarg "orange";
  • Some("banana")"chinese gooseberry";
  • None如果我调用它"apple"(没有以前的元素存在)或"potato"(不存在于列表中).

很容易完成,但我怎么能以优雅的功能方式做到这一点?我能想到的最好的是以下内容:

def previous(fruit: String, fruits: List[String]): Option[String] =
  fruits.sliding(2)
  .filter { case List(previous, current) => current == fruit }
  .toList
  .headOption
  .map { case List(previous, current) => previous }
Run Code Online (Sandbox Code Playgroud)

它有效,但它不优雅或高效.我特别讨厌转换filter迭代器toList.我怎样才能改进它?

(*作为一个旁边,是List用于sliding迭代的最佳集合?)

Mic*_*jac 12

这是一个较短的版本使用collectFirst:

def previous(fruit: String, fruits: List[String]): Option[String] =
    fruits.sliding(2).collectFirst{ case List(previous, `fruit`) => previous}
Run Code Online (Sandbox Code Playgroud)

注意周围的反引号fruit以匹配参数值.使用collectFirst也将在第一个匹配时停止,而不是在整个迭代器中运行filter.


ste*_*tew 8

我认为这是一种直接递归和模式匹配既高效又易于阅读的情况:

@annotation.tailrec
def getPrevious(fruit: String, fruits: List[String]): Option[String] = fruits match  {
  case Nil               => None
  case x :: `fruit` :: _ => Some(x)
  case _ :: xs           => getPrevious(fruit, xs)
}
Run Code Online (Sandbox Code Playgroud)