2013-03-28 77 views
0

林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 
    } 
} 

我可以使它只工作在平凡的情況。

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

回答

3
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 
+0

+1表示@tailrec,因爲這是處理「下一個」的更直接簡單的方法。 – wheaties 2013-03-28 03:52:24

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

注意,如果在草堆中找到匹配,不像你上面的例子返回值爲None。該函數的結果,然後可以用默認的回答結合起來,就像這樣:

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

對於'FindNext中(3,列表(1,2,3))== 1'此返回'選項[INT] = None'其中示例顯示它返回'haystack'的頭部。 – Brian 2013-03-28 03:52:33

+2

添加了關於此的註釋。我不確定作者是否打算這樣做。 – 2013-03-28 03:57:19

+0

@alexwriteshere是的,「FindNext中」動作應該是圓形的。這雖然是巨大的幫助。 – Tom 2013-03-28 04:03:50

1

這個圈子回到原來haystack的頭,如果最後一個元素是needleif條件語句的幫助。該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)