程式扎記: [Scala 小學堂] Scala Gossic : 繼續深入 - 模式比對 (List 與 Tuple 模式)

標籤

2016年7月9日 星期六

[Scala 小學堂] Scala Gossic : 繼續深入 - 模式比對 (List 與 Tuple 模式)

Source From Here 
List 與 Tuple 模式
List 可以用於模式比對,最基本的形式就是直接比較元素內容:
  1. def what(a: Any) = a match {  
  2.     case List(1)       => "元素 1"  
  3.     case List(12)    => "元素 1 2"  
  4.     case List(12, _) => "元素 1 2 以及第三個"  
  5.     case _             => "別的東西"  
  6. }  
  7.   
  8. println(what(List(1)))        // 元素 1  
  9. println(what(List(12)))     // 元素 1 2  
  10. println(what(List(123)))  // 元素 1 2 以及第三個  
  11. println(what(List(124)))  // 元素 1 2 以及第三個  
前兩個 case 完全比對 List 中的元素,第三個 case 因為結合了萬用字元模式,所以只要前兩個元素為1、2,而第三個元素不管是什麼都可以。下面則是另一個例子:
  1. def what(a: Any) = a match {  
  2.     case List(12, x) => "元素 1 2 以及 " + x  
  3.     case List(2, _*)   => "首個元素 2 的 List"  
  4.     case List(3, _*)   => "首個元素 3 的 List"  
  5.     case _             => "別的東西"  
  6. }  
  7.   
  8. println(what(List(123)))       // 元素 1 2 以及 3  
  9. println(what(List(124)))       // 元素 1 2 以及 4  
  10. println(what(List(224)))       // 首個元素 2 的 List  
  11. println(what(List(32456))) // 首個元素 3 的 List  
第一個 case 結合了變數模式,取得 List 第三個元素並指定給 x。第二與第三個 case 使用了萬用字元模式,而 * 表示不管有幾個元素,所以第二個 case 比對的是,只要首個元素是 2 的 List,第三個 case 比對的是只要首個元素是 3 的 List

List 有 head 方法,可以傳回 List 中首個元素,也有個 tail 方法,可以傳回 List 除首個元素外,其它元素的陣列,例如:
scala> val list = List(1, 2, 3, 4, 5)
list: List[Int] = List(1, 2, 3, 4, 5)

scala> list.head
res0: Int = 1

scala> list.tail
res1: List[Int] = List(2, 3, 4, 5)
在模式比對中,可以使用 :: 來同時取得 head 與 tail,例如:
  1. def what(a: Any) = a match {  
  2.     case Nil        => "空串列"  
  3.     case head::tail => "首元素:" + head + ", 其它元素:" + tail  
  4.     case _          => "別的東西"  
  5. }  
  6. println(what(List()))               // 空串列  
  7. println(what(List(123)))        // 首元素:1, 其它元素:List(2, 3)  
  8. println(what(List(124)))        // 首元素:1, 其它元素:List(2, 4)  
  9. println(what(List(224)))        // 首元素:2, 其它元素:List(2, 4)  
  10. println(what(List(32456)))  // 首元素:3, 其它元素:List(2, 4, 5, 6)  
  11. println(what(Nil))                  // 空串列  
  12. println(what(Array(123)))       // 別的東西  
:: 可以連續組合,最後一個是尾端所有元素,例如:
  1. def what(a: Any) = a match {  
  2.     case Nil        => "空串列"  
  3.     case x::y::tail => "首元素:" + x + ", 次元素:" + y + ", 其它元素:" + tail  
  4.     case _          => "別的東西"  
  5. }  
  6.   
  7. println(what(List(123)))       // 首元素:1, 次元素:2, 其它元素:List(3)  
  8. println(what(List(124)))       // 首元素:1, 次元素:2, 其它元素:List(4)  
  9. println(what(List(224)))       // 首元素:2, 次元素:2, 其它元素:List(4)  
  10. println(what(List(32456))) // 首元素:3, 次元素:2, 其它元素:List(4, 5, 6)  
再來看看 Tuple 模式的運用:
  1. def what(a: Any) = a match {  
  2.     case (12)         =>  "(1, 2)"  
  3.     case (_, _, x)      =>  "三個元素 Tuple,第三個元素為 " + x  
  4.     case _              =>  "別的東西"  
  5. }  
  6.   
  7. println(what((12)))      // (1, 2)  
  8. println(what((124)))   // 三個元素 Tuple,第三個元素為 4  
同樣地,Tuple 模式中還結合了 萬用字元模式 以 及變數模式。事實上,模式還可以運用於 變數指定,例如以下將函式傳回的 Tuple 元素指定給 xyz 的方式,就是一種模式運用:
  1. def some = (123)  
  2.   
  3. val (x, y, z) = some  
  4. println(x)   // 1  
  5. println(y)   // 2  
  6. println(z)   // 3  
  7.   
  8. val (a, b, _) = some  
  9. println(a)   // 1  
  10. println(b)   // 2  
List 也有同樣的應用:
  1. def some = List(1234)  
  2.   
  3. val List(w, x, y, z) = some  
  4. println(w)    // 1  
  5. println(x)    // 2  
  6. println(y)    // 3  
  7. println(z)    // 4  
  8.   
  9. val List(a, _*) = some  
  10. println(a)    // 1  
  11.   
  12. val head::tail = some  
  13. println(head) // 1  
  14. println(tail) // List(2, 3, 4)  
事實上,只要是 案例類別,也可以有類似的指定方式:
  1. case class Point(x: Int, y: Int)  
  2. case class Circle(p: Point, r: Int)  
  3.   
  4. def some = Point(12)  
  5. def other = Circle(Point(34), 5)  
  6.   
  7. val Point(x, y) = some  
  8. println(x)    // 1  
  9. println(y)    // 2  
  10.   
  11. val Circle(p, _) = other  
  12. println(p)    // Point(3, 4)  
事實上,List 的 head::tail 模式比對,其實就是建構式模式比對,當你使用 head::tail 模式比對時,其實是在作 ::(head, tail) 模式比對:
  1. def some = List(1234)  
  2.   
  3. val head1::tail1 = some  
  4. println(head1)    // 1  
  5. println(tail1)    // List(2, 3, 4)  
  6.   
  7. val ::(head2, tail2) = some  
  8. println(head2)    // 1  
  9. println(tail2)    // List(2, 3, 4)  
Scala 確實定義了 scala.:: 案例類別:


其實只要是 案例類別,建構式模式 都可以寫成中置運算形式,例如:
  1. case class Point(x: Int, y: Int)  
  2. case class Circle(p: Point, r: Int)  
  3.   
  4. def some = Point(12)  
  5. def other = Circle(Point(34), 5)  
  6.   
  7. val x Point y = some  
  8. println(x)    // 1  
  9. println(y)    // 2  
  10.   
  11. val p Circle _ = other  
  12. println(p)    // Point(3, 4)  
最主要的是寫成這種形式,對可讀性有無幫助,scala.:: 建構式模式比對時,寫為 head::tail 形式,主要是可對應至 List 所提供的 :: 方法,因此寫為中置運算形式直覺且易讀。在 for 迴圈中,也可以運用模式,例如:
  1. val list1 = List((101"Justin"), (102"momor"))  
  2. for((room, name) <- list1="" nbsp="" span="">
  3.     printf("%d, %s%n", room, name)  
  4. }  
  5.   
  6. case class Point(x: Int, y: Int)  
  7. val list2 = List(Point(00), Point(11), Point(22))  
  8. for(Point(x, y) <- list2="" nbsp="" span="">
  9.     printf("%d, %d%n", x, y)  
  10. }  
現在你應該可以看懂 match 運算式 最後例子中的模式是怎麼回事了:
  1. object Sort {  
  2.     def quick(list: List[Int]): List[Int] = {  
  3.        list match {  
  4.            case Nil => Nil       
  5.            case x::xs =>          
  6.            val (before,after) = xs partition (_ < x)  
  7.            quick(before) ++ (x :: quick(after))  
  8.        }  
  9.     }  
  10. }  
上面的函式 partition(p: (A) ⇒ Boolean): (List[A], List[A]) 為 List 上面的方法:
scala> val list = List(1, 2, 3, 4, 5, 6)
list: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> list.partition(_ > 3)
res0: (List[Int], List[Int]) = (List(4, 5, 6),List(1, 2, 3))

scala> list partition (_ < 3)
res1: (List[Int], List[Int]) = (List(1, 2),List(3, 4, 5, 6))

而 ++ (Returns a new list containing the elements from the left hand operand followed by the elements from the right hand operand.) 也是 List 上面的方法:
scala> val list2 = List(11, 12, 13, 14, 15)
list2: List[Int] = List(11, 12, 13, 14, 15)

scala> list ++ list2 // list.++(list2)
res2: List[Int] = List(1, 2, 3, 4, 5, 6, 11, 12, 13, 14, 15)

This message was edited 18 times. Last update was at 09/07/2016 19:12:37

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!