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

时间:2014-07-31 01:28:19

标签: scala scala-collections

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

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

  • Some("apple")如果我使用fruit arg "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 }

它有效,但它不优雅或高效。我特别讨厌转换filter迭代器toList。我该如何改进呢?

(*另外,List是用于sliding次迭代的最佳集合吗?)

3 个答案:

答案 0 :(得分:12)

这是使用collectFirst的较短版本:

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

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

答案 1 :(得分: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)
}

答案 2 :(得分:1)

首先想到的解决方案是:

import scala.util.Try
def previous(fruit: String, fruits: List[String]) = Try(fruits(fruits.indexOf(fruit) - 1)).toOption

当然应该有效率更高。