【问题标题】:Given an element in a sequence, how to get the previous element?给定序列中的一个元素,如何获取前一个元素?
【发布时间】:2014-09-22 20:20:00
【问题描述】:

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

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

  • Some("apple") 如果我用 fruit arg of "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 迭代的最佳集合吗?)

【问题讨论】:

    标签: scala scala-collections


    【解决方案1】:

    想到的第一个简单的解决方案是:

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

    当然应该有更高效的。

    【讨论】:

    • 这看起来很聪明,但是抛出异常的成本很高 + 异常应该在异常情况下使用,它们不是违反 FP 原则的值。尽管如此,我还是喜欢这个主意;)
    • 是的,我知道,在最坏的情况下,它还会迭代整个 List 两次。可悲的是,O(n) 上的索引是 List。这只是一个疯狂的想法。 ;)
    【解决方案2】:

    这是使用collectFirst 的较短版本:

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

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

    【讨论】:

      【解决方案3】:

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

      @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)
      }
      

      【讨论】:

      • 完全同意第二点 - 这对我来说更具可读性。
      猜你喜欢
      • 2021-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多