前言
本節介紹除List之外的其他集合類型,如Set、Map。
1. 序列
序列類型可以用來處理依此排列分組的數據。由於元素是有次序的,所以可以使用下標如1、2、3…等訪問。
-
列表
如果看過《13-使用列表》,應該對列表比較熟悉了,這裏使用一個簡單例子:
-
數組
衆多的方法:
-
列表緩衝(list buffer)
ListBuffer是看一遍對象,在需要追加元素來構建列表時更加高效。
使用 += 往後追加,使用 +=: 往前追加。
如:
-
數組緩衝(ArrayBuffer)
-
字符串(StringOps)
StringOps實現了很多序列方法。由於Predef有一個從String到StringOps的隱式轉換,可以將任何字符串當作序列處理,如:
字符串本身並沒有"exists"方法,Scala編譯器會隱式地將s 轉換成StringOps,在StringOps 中有exists方法。exists方法將字符串當做字符序列。
2. 集和映射
在Scala中默認的Set和Map是不可變類型。如果需要使用可變類型,需要引入。如果直接引入可變類型的類名,將會覆蓋不可變類型。所以,通常是引入可變類型所在包的包名,如:
集
集裏的每一個對象最多出現一次,如下面例子:統計字符串中出現的不同的單詞。
將字符串單詞分割出來:
17.1.scala
// 統計不同單詞
val text = "Hello world. Hello scala!"
val wordsArr = text.split("[ !,.]+") // 參數爲正則表達式
由於集可以自動過濾重複項,所以只需要把分割的單詞加入集即可:
17.1.scala
// 創建空集
val words = mutable.Set.empty[String]
for (word <- wordsArr) {
words += word.toLowerCase
}
words
其他操作:(手機拍攝不是很清晰)
映射
可變映射的基本操作:
例子,統計字符串中每個單詞出現的次數:
17.1.scala
def countWords(text: String) = {
val counts = mutable.Map.empty[String, Int]
for (rawWord <- text.split("[ ,!.]+")) {
val oldCount = {
if (counts.contains(rawWord)) counts(rawWord)
else 0
}
// 計數
counts += (rawWord -> (oldCount + 1))
}
counts
}
常用方法:
默認的集和映射
對於可變集合映射,返回對象內部都使用到了哈希表。返回對象分別爲HashSet 和 HashMap。因爲使用到了哈希表,所以可以很快判斷某個對象是否在集合中。
對於不可變集合而言,相對較複雜。
對於少於5個元素的集,有各自對應的返回對象,5個及以上返回HashSet和HashMap,如:
測試:
單獨的對象能夠帶來最佳的性能。
排好序的集和映射
Scala集合類庫提供了SortedSet 和 SortedMap 特質。這些特質被TreeSet和TreeMap類實現。如:
3. 在可變和不可變集合類之間選擇
Scala支持可變和不可變集合,但是更加推薦不可變集合。
當然,Scala也支持可變與不可變集合之間的相互轉換。
如,不可變集合映射並不真正支持 += 操作,但Scala提供了一個變通的解讀:只要看到 a += b,而a 並不支持名爲 += 的方法,Scala會嘗試把它解讀爲 a = a + b。
測試:
這樣操作你會發現報錯。原因就是:不可變Set 沒有 += 方法,所以Scala 編譯器會翻譯爲 aset = aset + 4。但是,aset 是val 不可修改變量,所以會報錯。因此,你可能猜到可以使用var 變量:
同理,-=、- -=、++=操作也是一樣的。
4. 初始化集合
相信簡單的初始化你已經沒有問題,下面介紹其他初始化方法。
-
從List 初始化
不能直接傳入一個列表對象。
需要創建空的TreeSet,使用 ++ 將列表元素添加:
其中, ++ 後面跟多個元素,+ 後面跟一個元素。 -
轉成數組或列表
注意:這裏轉換後的元素是有序的。 -
在可變和不可變集和映射間轉換
這裏用一個示例:把TreeSet轉換爲可變集,然後把可變集轉爲不可變集。
注意,這裏轉換後是無序的。
同樣,也可以將不可變轉換爲可變類型:
5. 元組
元組不同於列表和數組,元組可以存放不同類型的元素,如:
示例,尋找字符串第一個最長字母及下標:
17.1.scala
// 尋找字符串第一個最長字母及下標
def longest(words: Array[String]) = {
var word = words(0)
var idx = 0
for (i <- 1 until words.length) {
if (words(i).length > word.length) {
word = words(i)
idx = i
}
}
(word, idx)
}
longest("Life is short, I use Python.".split("[ ,.]"))
關於元組的一些操作:
解元組(模式匹配的一個特例):
這裏有加不加括號的區別。