【问题标题】:Finding next element in List using pattern matching使用模式匹配查找 List 中的下一个元素
【发布时间】:2013-03-18 09:52:34
【问题描述】:

我正在玩 scala 模式匹配,试图创建一个 findNext 函数:

findNext(1,List(1,2,3)) == 2
findNext(2,List(1,2,3)) == 3
findNext(3,List(1,2,3)) == 1

def findNext(needle : Int, haystack : List[Int]): Int = {
    haystack match {
       case Nil => /* handle it */
       case needle::Nil => needle
       case front::needle::back => back.head
       case needle::back::Nil => back.head
    }
}

我可以让它只适用于微不足道的情况。

这可以使用模式匹配来完成吗?我知道我可以使用列表中的方法使其工作,但这只是一个玩具程序。

【问题讨论】:

    标签: list scala pattern-matching


    【解决方案1】:
    def findNext(needle : Int, haystack : List[Int]): Option[Int] = {
      @annotation.tailrec def loop(needle : Int, haystack : List[Int], trueHead: Int): Option[Int] =
        haystack match {
          case Nil => None
          case `needle` :: next :: _ => Some(next)
          case `needle` :: Nil => Some(trueHead)
          case _ :: tail => loop(needle, tail, trueHead)
        }
      haystack match {
        case Nil | _ :: Nil => None
        case _ => loop(needle, haystack, haystack.head)
      }
    }
    

    请参阅this answer 以了解模式匹配中的反引号。

    用法:

    scala> findNext(1,List(1,2,3))
    res0: Option[Int] = Some(2)
    
    scala> findNext(2,List(1,2,3))
    res1: Option[Int] = Some(3)
    
    scala> findNext(3,List(1,2,3))
    res2: Option[Int] = Some(1)
    
    scala> findNext(4,List(1,2,3))
    res3: Option[Int] = None
    
    scala> findNext(1,List(1,1))
    res4: Option[Int] = Some(1)
    
    scala> findNext(1,List(1))
    res5: Option[Int] = None
    
    scala> findNext(1,List())
    res6: Option[Int] = None
    

    【讨论】:

    • +1 建议使用@tailrec,因为这是处理“下一个”的更直接和简单的方法。
    【解决方案2】:

    由于可能找不到针,因此最好在此处返回Option[Int]。仅使用模式匹配,您可以通过以下方式解决它:

    @tailrec def findNext(needle: Int, haystack: List[Int]): Option[Int] = {
        haystack match {
          case Nil => None
          case front::next::back if front == needle => Some(next)
          case head::tail => findNext(needle, tail)
        }
      }
    

    甚至更简单:

      @tailrec def findNext(needle: Int, haystack : List[Int]): Option[Int] = {
        haystack match {
          case Nil => None
          case head::tail if head == needle => tail.headOption
          case head::tail => findNext(needle, tail)
        }
      }
    

    请注意,如果在 haystack 中找不到匹配项,则返回 None,这与上面的示例不同。然后可以将函数的结果与默认答案结合起来,如下所示:

    val haystack = List(1,2,3,4)
    findNext(4, haystack) getOrElse haystack.head
    

    【讨论】:

    • 对于findNext(3,List(1,2,3)) == 1,这将返回Option[Int] = None,示例显示它返回haystack 的头部。
    • 添加了一个注释。我不确定作者是否有意这样做。
    • @alexwriteshere 是的,“findNext”操作应该是循环的。不过,这帮助很大。
    • findNext(4, List(1)) getOrElse haystack.head == 1
    【解决方案3】:

    如果最后一个元素是 needleif 条件的帮助下,这会回到原始 haystack 的头部。 findNextR 保存最后一个元素是needle 的情况下的值。

    def findNext(needle: Int, haystack: List[Int]): Option[Int]  =  {
      @annotation.tailrec def findNextR(needle: Int, haystack: List[Int], savedHead: Int): Option[Int]  =  {
        haystack match{
          case Nil => None
          case head :: tail => if (head == needle && tail.isEmpty) Some(savedHead)
                                       else if (head == needle) Some(tail.head)
                                       else findNextR(needle, tail, savedHead)
        }
      }
     findNextR(needle, haystack, haystack.head)
    }
    
    scala> :load findNext.scala
    Loading findNext.scala...
    findNext: (needle: Int, haystack: List[Int])Option[Int]
    
    scala> findNext(1, List(1,2,3))
    res0: Option[Int] = Some(2)
    
    scala> findNext(2, List(1,2,3))
    res1: Option[Int] = Some(3)
    
    scala> findNext(3, List(1,2,3))
    res2: Option[Int] = Some(1)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-22
      • 1970-01-01
      • 2014-08-20
      • 1970-01-01
      • 2016-07-02
      • 2014-07-19
      • 1970-01-01
      相关资源
      最近更新 更多