2016年4月27日 星期三

[Scala 小學堂] Scala Gossic : 起步走 - 常用物件 (Array)

轉載自 這裡 
前言 : 
Scala 是一個可直譯、編譯、靜態、運行於 JVM 之上、可與 Java 互操作、融合物件導向編程特性與函式編程風格的程式語言. 從一些簡單的語法開始,了解 Scala 的許多特性,所以就算是起步走,東西也夠多了. 簡單的小程式可以使用 scala 指令,編譯的事就交給 scalac,編譯想快點就用 fsc. (Scala 官網), 在變與不變之間,先體會 Scala 更多特性. 

Array : 
在 Scala 中,如果要建立陣列,可以使用 Array 類別,建立陣列時,須指定陣列後存放的元素型態. 如以下建立長度為 5,內含Int、Double、Boolean、String等指定型態的陣列 : 
scala> val arr1 = new Array[Int](5)
arr1: Array[Int] = Array(0, 0, 0, 0, 0)

scala> val arr2 = new Array[Double](5)
arr2: Array[Double] = Array(0.0, 0.0, 0.0, 0.0, 0.0)

scala> val arr2 = new Array[Char](5)
arr2: Array[Char] = Array(?, ?, ?, ?, ?)

scala> val arr2 = new Array[Boolean](5)
arr2: Array[Boolean] = Array(false, false, false, false, false)

scala> val arr2 = new Array[String](5)
arr2: Array[String] = Array(null, null, null, null, null)


在建立陣列之後,如果內含元素是整數,則預設值為 0,浮點數則預設值為 0.0,字元則預設值為空字元(字元編碼為0的字元),布林值預設為 false,其它型態則預設值為 null(與 Java 的陣列類似). 如果要多維陣列,基本上是以一維陣列來摸擬,例如要建立二維陣列 : 
scala> val arr=new Array[Array[Int]](5,5)
warning: there were deprecation warnings; re-run with -deprecation for details
arr: Array[Array[Int]] = Array(Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0))

如果要存取陣列,必須指定陣列索引,與其它語言存取陣列慣例不同的是,在 Scala 中,指定陣列索引時是使用 () 而非 [],例如 : 
- Array1.scala 代碼 :
  1. val arr = new Array[Int](3)  
  2. arr(0) = 10  
  3. arr(1) = 20  
  4. arr(2) = 30  
  5. println(arr(0)) // 顯示 10  
  6. println(arr(1)) // 顯示 20  
  7. println(arr(2)) // 顯示 30  

事實上,當你使用 arr(0) = 10 這樣的指定方式時,Scala 會將之轉換為呼叫陣列的 update() 方法,而你用 arr(0) 的方式要取得指定索引的元素時,Scala 會將之轉換為呼叫 apply 方法。以下是個簡單的驗證方式 : 
- Array2.scala 代碼 :
  1. val arr = new Array[Int](3)  
  2. arr.update(010)  
  3. arr.update(120)  
  4. arr.update(230)  
  5. println(arr.apply(0)) // 顯示 10  
  6. println(arr.apply(1)) // 顯示 20  
  7. println(arr.apply(2)) // 顯示 30  

在 Scala 中,指定索引進行存取時使用 () 而不是 [],其實是為了語法的一致性。這種在 () 中指定索引進行存取的方式,並非只有陣列專屬,只要是有提供 update() 或 apply() 方法的物件,其實都可以使用這樣的存取方式,像是在 String 也曾經使用過這樣的方式 : 
  1. val str = "Scala"  
  2. println(str(0)) // 顯示 'S'   
  3. println(str(1)) // 顯示 'c'   
  4. println(str(2)) // 顯示 'a'   
  5. println(str(3)) // 顯示 'l'   
  6. println(str(4)) // 顯示 'a'  
如果你要在建立陣列時,一併指定元素值,則可以直接使用以下的語法 : 
- Array3.scala 代碼 :
  1. val arr = Array(102030)  
  2. for(i <- nbsp="" span="">0 until arr.length) {  
  3.     println(arr(i))  
  4. }  

其實在 單例物件 中有介紹過了,Array(10, 20, 30) 這樣的寫法是個語法蜜糖,Scala 會將之轉換為呼叫 scala.Array 伴侶物件的 apply 方法,這個方法會傳回含指定元素的陣列。以下這個程式可以驗證這個說法 : 
- Array4.scala 代碼 :
  1. val arr = Array.apply(102030)  
  2. for(i <- arr="" nbsp="" span="">
  3.     println(i)  
  4. }  

上面這個範例程式,同時示範了迭代陣列的另一種方式,每一次迭代,都會將 arr 的元素取出指定給i。事實上,陣列提供 foreach 方法可以使用,上面的程式你可以這麼撰寫 : 
- Array5.scala 代碼 :
  1. val arr = Array(102030)  
  2. arr.foreach((i: Int) => println(i))  

在 簡單的函式 中有介紹過,foreach中是函式字面寫法,執行時期會傳入函式物件,每次取出一個元素,就會呼叫函式物件。你可以利用類型推斷,讓這個範例更簡短一些 : 
- Array6.scala 代碼 :
  1. val arr = Array(102030)  
  2. arr.foreach(i => println(i))  

arr.foreach(i => println(i)) 其實是 arr.foreach((i) => println(i)) 簡寫,因為只有一個參數,所以括號可以省略。事實上,就上面這個例子來說,最簡短的寫法是 : 
- Array7.scala 代碼 :
  1. val arr = Array(102030)  
  2. arr.foreach(println)  

事實上,foreach 中是 部份套用函式(Partially applied function)的寫法,這之後還會詳述. 像 foreach 這種傳入函式物件執行某個操作的作法,在 Scala 相當常見。例如陣列的 filter 方法,可以傳入一個會運算出布林值的函式物件,根據真或假決定結果要包括哪些元素,例如 : 
- Array8.scala 代碼 :
  1. val arr = Array(102030405060)  
  2. arr.filter(x => x > 30).foreach(println)  

事實上,上面這個程式可以使用佔位字元語法(Placeholder syntax)撰寫為以下的方式 : 
- Array9.scala 代碼 :
  1. val arr = Array(102030405060)  
  2. arr.filter(_ > 30).foreach(println) // 逐行顯示 40、50、60  

_ 作為佔位字元,就目前來說,你可以將看它看作是填充欄位,每一次取得的元素值將值入這個欄位其實完整的語法應該是 (_ : Int) > 30,不過由於利用了類型推斷,所以可以推斷出_應該是 Int,因此可以寫為 _ > 30,佔位字元語言之後還會詳述). 
類似地,如果你不僅是想過濾,還想對元素作某些運算後傳回的話,則可以使用 map 方法,例如將每個元素加 1 後傳回新陣列 : 
- Array10.scala 代碼 :
  1. val arr = Array(102030)  
  2. arr.map(_ + 1).foreach(println) // 逐行顯示 11、21、31  

陣列可以串接,不過不是使用 +,而是使用 ++這是 Array 上定義的方法),這會將兩個陣列的元素取出,建立一個新陣列後傳回。例如 : 
scala> val arr1 = Array(10, 20, 30)
arr1: Array[Int] = Array(10, 20, 30)

scala> val arr2 = Array(40, 50, 60)
arr2: Array[Int] = Array(40, 50, 60)

scala> val arr3 = (arr1 ++ arr2)
arr3: Array[Int] = Array(10, 20, 30, 40, 50, 60) 
scala> arr3.foreach(x => print(x + " ")); println()
10 20 30 40 50 60

如果你要比較兩個陣列的內含值是否相同,由於要逐一比對陣列中每個陣列的元素物件內含值,所以不能直接使用 == 比較,而要使用 deepEquals 方法。例如 : 
scala> val arr1 = Array(10, 20, 30)
arr1: Array[Int] = Array(10, 20, 30)

scala> val arr2 = Array(10, 20, 30)
arr2: Array[Int] = Array(10, 20, 30)

scala> arr1 == arr2
res1: Boolean = false

scala> arr1 deepEquals arr2
warning: there were 1 deprecation warnings; re-run with -deprecation for details
res2: Boolean = true


scala> arr1.deep
res3: IndexedSeq[Any] = Array(10, 20, 30)

scala> arr2.deep
res4: IndexedSeq[Any] = Array(10, 20, 30)

scala> arr1.deep.equals(arr2.deep)
res5: Boolean = true

Supplement 
Tutorialspoint - Scala Arrays

沒有留言:

張貼留言

[Git 文章收集] Differences between git merge and git rebase

Source From  Here Preface Merging and rebasing are the two most popular way to applying changes from one branch into another one. They bot...