數組相關操做 |
原地址:http://www.cnblogs.com/sunddenly/p/4411564.htmlhtml
摘要:前端
本篇主要學習如何在Scala中操做數組。Java和C++程序員一般會選用數組或近似的結構(好比數組列表或向量)來收集一組元素。在Scala中,咱們的選擇更多,不過如今咱們先假定不關心其餘選擇,而只是想立刻開始用數組。本篇的要點包括:java
1. 若長度固定則使用Array,若長度可能有變化則使用ArrayBuffer程序員
2. 提供初始值時不要使用new算法
3. 用()來訪問元素編程
4. 用for (elem<-arr)來遍歷元素數組
5. 用for (elem<-arr if…)…yield…來將原數組轉型爲新數組數據結構
6. Scala數組和java數組能夠互操做;用AnayBuffer,使用scalacollection.JavaConversions中的轉換函數函數式編程
定長數組函數 |
若是你須要一個長度不變的數組,能夠用Scala中的Array。例如:
val nums=new Array[Int] (10) //長度爲10的整數數組,全部元素初始化爲0
val a=new Array [String] (10) //長度爲10的字符串數組,全部元素初始化爲null
val s= Array("Hello", "World") //長度爲2的Array[String]類型是推斷出來的,已提供初始值就不須要new
S (0) ="Goodbye" //Array("Goodby ","World"),使用()而不是[]來訪問元素
在JVM中,Scala的Array以Java數組方式實現。示例中的數組在JVM中的類型爲java.lang.String[]。Int、Double或其餘與Java中基本類型對應的數組都是基本類型數組。
舉例來講,Array(2,3,5,7,11)在JVM中就是一個int[]。
變長數組:緩衝 |
尾端操做緩衝數組
對於那種長度按須要變化的數組,Java有ArrayList,C++有vector。Scala中的等效數據結構爲ArrayBuffer
import scala.collection.mutable.ArrayBuffer
val b=ArrayBuffer[lnt]() // 或者new ArrayBuffer [int],一個空的數組緩衝,準備存放整數
b+=1 // ArrayBuffer (1),用+=在尾端添加元素
b+=(1,2,3,5) // ArrayBuffer(1,1,2,3,5),在尾端添加多個元素,以括號包起來
b++= Array(8, 13, 21) // ArrayBuffer(1, 1, 2, 3, 5, 8,13, 21) //用++=操做符追加任何集合
b.trimEnd(5) // ArrayBuffer(1, 1, 2),移除最後5個元素
在數組緩衝的尾端添加或移除元素是一個高效的操做
任意位置操做緩衝數組
你也能夠在任意位置插入或移除元素,但這樣的操做並不那麼高效。全部在那個位置以後的元素,都必須被平移。舉例以下:
b.insert (2,6) //ArrayBuffer(1, 1, 6, 2),在下標2以前插入
b.insert (2,7,8,9) // ArrayBuffer(1, 1,7,8,9, 6,2),你能夠插入任意多的元素
b.remove(2) // ArrayBuffer(1,1,8,9,6,2)
b.remove (2,3) //ArrayBuffer(1,1, 2),第2個參數的含義是要移除多少個元素
有時你須要構建一個Array,但不知道最終須要裝多少元素。在這種狀況下,先構建一個數組緩衝,而後調用:
b.toArray //Array(1, 1,2)
反過來,調用亂toBuffer能夠將一個數組a轉換成一個數組緩衝
遍歷數組和數組緩衝 |
全遍歷
在Java和C++中,數組和數組列表/向量有一些語法上不一樣,Scala則更加統一。大多數時候,你能夠用相同的代碼處理這兩種數據結構。如下是for循環遍歷數組或數組緩衝的語法:
for (i <- 0 until a.length) //變量i的取值從0到a length -1
println(i+":"+a(i))
utiI是Richlnt類的方法,返回全部小於但不包括上限的數字。例如:
0 until 10 // Range(0,1,2,3,4,5,6,7,8, 9)
須要注意的是,0 until 10其實是一個方法調用:0.until(10)
條件遍歷
以下結構:
for(I <- 區間)
會讓變量i遍歷該區間的全部值。拿本例來講,循環變量i前後取值0、1,等等,直到但不包含a.length。若是想要每兩個元素一跳,可讓i這樣來進行遍歷:
0 until (a.length,2) //Range(0,2,4,…)
若是要從數組的尾端開始,遍歷的寫法爲:
(0 until a.length) .reverse //Range(...,2,1,0)
若是在循環體中不須要用到數組下標,咱們也能夠直接訪問數組元素,就像這樣:
for (elem <- a)
println (elem)
這和Java中的"加強版"for循環,或者C++中的"基於區間的"for循環很類似。變量elem前後被設爲a(0),而後a(1),依此類推
數組轉換 |
for中的推導式和守衛
在前面,你看到了如何像Java或C++那樣操做數組。不過在Scala中,你能夠走得更遠。從一個數組或數組緩衝出發,以某種方式對它進行轉換是很簡單的。這些轉換動做不會修改原始數組,而是產生一個全新的數組。像這樣使用for推導式:
val a=Array(2, 3, 5, 7, 11)
val result=for (elem <- a) yield 2*elem //result是Array(4,6,10, 14, 22)
for(…)yield循環建立了一個類型與原始集合相同的新集合。若是你從數組出發,那麼你獲得的是另外一個數組。若是你從數組緩衝出發,那麼你在for(…)yield以後獲得的也
是數組緩衝
結果包含yield以後的表達式的值,每次迭代對應一個。一般,當你遍歷一個集合時,你只想處理那些知足特定條件的元素。這個需求能夠經過守衛:for中的if來實現。在這裏咱們對每一個偶數元素翻倍,並丟掉奇數元素:
for (elem <- a if elem%==0) yield 2*elem
請留意結果是個新的集合,原始集合並無受到影響
一種等價方法
除上述以外,還有另外一種作法是
a.filter (_%2==0).map(2*_)
甚至
a.filter { _%2 == 0 } map {2*_ }
某些有着函數式編程經驗的程序員傾向於使用filter和map而不是守衛和yield,這不過是一種風格罷了與for循環所作的事徹底相同。你能夠根據喜愛任意選擇。
高效數組操做
考慮以下示例:給定一個整數的數組緩衝,咱們想要移除除第一個負數以外的全部負數。傳統的依次執行的解決方案會在遇到第一個負數時置一個標記,而後移除後續出現的負數元素
var first=true
var n=a.length
var i=0
while ( i<n ) {
if (a(i) >= 0)
i+=1
else{
if (first) {
first=false
i+=1
} else {
a.remove (i)
n-=1
}
}
}
但這個方案其實並不那麼好:從數組緩衝中移除元素並不高效,把非負數值拷貝到前端要好得多。
首先收集須要保留的下標:
var first= true
val indexes=for (i <- 0 until a.length if first || a(i)>=0) yield {
if (a(i)<0)
first=false;
i
}
而後將元素移動到該去的位置,並截斷尾端:
for(j <- 0 until indexes.length)
a(j)= a(indexes(j))
a.trimEnd (a.length -indexes.length)
這裏的關鍵點是,拿到全部下標好過逐個處理
經常使用算法 |
求和與排序
有一種說法,很大比例的業務運算不過是在求和與排序。還好Scala有內建的函數來處理這些任務
Array(1,7,2, 9).sum // 19,對ArrayBuffer一樣適用
要使用sum方法,元素類型必須是數值類型:要麼是整型,要麼是浮點數或者Biglnteger/BigDecimal。
同理,min和max輸出數組或數組緩衝中最小和最大的元素。
ArraryBuffer("Mary", "had","a","little", "lamb").max // "little"
sorted方法將數組或數組緩衝排序並返回通過排序的數組或數組緩衝,這個過程並不會修改原始版本:
val b=ArrayBuffer(1,7,2, 9)
val bSorted=b.sorted(_ < _) // b沒有被改變,bSorted是ArrayBuffer(1,2,7,9)
還能夠提供一個比較函數,不過你須要用sortWith方法:
val bDescending=b.sorted(_ > _) // ArrayBuffer(9,7,2, 1)
能夠直接對一個數組排序,但不能對數組緩衝排序:
val a=Array(1,7,2,9)
scala.util. Sorting.quickSortIa(a) // a如今是Array(1,2,7,9)
關於num、max和quickSort方法,元素類型必須支持比較操做,這包括了數字、字符串以及其餘帶有Ordered特質的類型。
顯示數組內容
最後,若是你想要顯示數組或數組緩衝的內容,能夠用mkString方法,它容許你指定元素之間的分隔符。該方法的另外一個重載版本可讓你指定前綴和後綴。例如:
a.mkString("and") // "1 and 2 and 7 and 9"
a.mkString("<" , "," , ">") // "<1,2,7,9>"
和toString相比:
a.toString // " [I@85b8d",這裏被調用的是Java的毫無心義的toString方法
b.toString // "ArrayBuffer(l,7,2, 9)",toString方法報告了類型,便於調試
解讀Scaladoc |
數組和數組緩衝有許多有用的方法,咱們能夠經過瀏覽Scala文檔來獲取這些信息。對Array類的操做方法列在ArrayOps相關條目下。從技術上講,在數組上應用這些操做以前,數組都會被轉換成ArrayOps對象。
因爲Scala的類型系統比java更豐富,在瀏覽Scala的文檔時,你可能會遇到一些看上去很奇怪的語法。所幸,你並不須要理解類型系統的全部細節就能夠完成不少有用
的工做。你能夠把下表用作"解碼指環"。
多維數組 |
和Java同樣,多維數組是經過數組的數組來實現的。舉例來講,Double的二維數組類型爲:
Array[Array[Double]]
要構造這樣一個數組,能夠用ofDim方法:
val matrix=Array.ofDim[Double](3,4) //三行,四列要訪問其中的元素,使用兩對圓括號:
matrix (row) (column) =42
你能夠建立不規則的數組,每一行的長度各不相同:
val triangle=new ArraylArray [Int] (10)
for (i <- 0 until triangle.length)
triangle(i)=new Array[lnt] (i+1)
與Java互操做 |
因爲Scala數組是用java數組實現的,你能夠在Java和Scala之間來回傳遞。若是你調用接受或返回java.utiI.List的Java方法,則固然能夠在Scala代碼中使用Java的ArrayList但那樣作沒什麼意思。你徹底能夠引入scala.collection.JavaConversions裏的隱式轉換方法。這樣你就能夠在代碼中使用Scala緩衝,在調用Java方法時,這些對象會被自動包裝成Java列表。
舉例來講,java.lang.ProcessBuilder類有一個以List<String>爲參數的構造器。如下是在Scala中調用它的寫法:
import scala.collection.JavaConversions.bufferAsJavaList
import scala.collection.mutable.ArrayBuffer
val command = ArrayBuffer("ls", "-al", "/home/cay")
val pb = new ProcessBuilder(command) // Scala到Java的轉換
Scala緩衝被包裝成了一個實現了java.util.List接口的Java類的對象。反過來說,當Java方法返回java.util.List時,咱們可讓它自動轉換成一個Buffer:
import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.mutable.Buffer
val cmd: Buffer[String] = pb.command() // Java到Scala的轉換
須要注意的是,不能使用ArrayBuffer——包裝起來的對象僅能保證是個Buffer。若是Java方法返回一個包裝過的Scala緩衝,那麼隱式轉換會將原始的對象解包出來。拿本例來講,cmd == command。☆☆
若是,您認爲閱讀這篇博客讓您有些收穫,不妨點擊一下右下角的【推薦】。
若是,您但願更容易地發現個人新博客,不妨點擊一下左下角的【關注我】。
若是,您對個人博客所講述的內容有興趣,請繼續關注個人後續博客,我是【Sunddenly】。本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。