[From] https://blog.csdn.net/gongxifacai_believe/article/details/81916659
1、Scala中的集合
Scala有一個非常通用豐富強大可組合的集合庫;集合是高階的,並擁有一大套操作方法。Scala的所有的集合類都可以在包 scala.collection 包中找到,其中集合類都是高級抽象類或特性。
Iterable[T] 是所有可遍歷的集合,它提供了迭代的方法(foreach)。
Seq[T] 是有序集合。
Set[T]是數學上的集合(無序且不重復)。
Map[T]是關聯數組,也是無序的。
Scala 集合類系統地區分了可變的和不可變的集合。
可變集合可以在適當的地方被更新或擴展,意味着你可以修改、添加、移除一個集合的元素。而不可變集合類,相比之下永遠不會改變。不過,你仍然可以模擬添加移除或更新操作。但是這些操作將在每一種情況下都返回一個新的集合,同時使原來的集合不發生改變。可變的集合類位於 scala.collection.mutable 包中,而不可變的集合位於 scala.collection.immutable.scala.collection 包中。集合既可以是可變的,也可以是不可變的。
官方文檔:http://www.scala-lang.org/docu/files/collections-api/collections.html
所有集合組件圖示如下:
2、Scala集合List和Set
Scala集合中的seq包含了:Range和ArrayBuffer以及List。這些組件區分了可變和不可變類型。
(1)創建list集合
val list = List(1,2,3,4,5)
(2)Scala中的list包含兩個部分,head+tail或head+Nil
list.head 代表返回第一個元素,list.tail 代表返回一個不包含第一個元素的集合,Nil代表空的list集合。
val list2 = 1::Nil
注意集合的順序,前面是元素后面是集合
val list3 = 2::list2
前面的元素就是新的list的head,后面的就是新的list的tail
(3)創建一個可變的list集合
val listBuffer = scala.collection.mutable.ListBufferInt
(4)添加元素
listBuffer += 2
listBuffer +=(3,4,5)
listBuffer ++= List(6,7,8)
listBuffer -= (4,7)
(5)list練習:指定前綴
需求:使用遞歸函數給list中的每個元素都加上指定的前綴,並且打印出加上前綴的元素。
注意:最后一個元素的時候它的tail就是Nil。
def dtor(list: List[Int], pfix: String){
if(list != Nil){
println(pfix + list.head)
dtor(list.tail,pfix)
}
}
(6)set集合創建
不可變集合:
val set = Set(1,2,3,4)
可變集合:
val s = scala.collection.mutable.Set(1,2)
添加元素:
不可變集合:+ ++ - –
可變集合:+= ++= -= --=
3、Scala集合Map與Tuple
(1)創建Map
創建一個不可變的Map:
val ages = Map(“Leo” -> 30, “Jen” -> 25, “Jack” -> 23)
ages(“Leo”) = 31
創建一個可變的Map:
val ages = scala.collection.mutable.Map(“Leo” -> 30, “Jen” -> 25, “Jack” -> 23)
ages(“Leo”) = 31
使用另外一種方式定義Map元素:
val ages = Map((“Leo”, 30), (“Jen”, 25), (“Jack”, 23))
創建一個空的HashMap:
val ages = new scala.collection.mutable.HashMap[String, Int]
(2)訪問Map的元素
獲取指定key對應的value,如果key不存在,會報錯:
val leoAge = ages(“Leo”)
val leoAge = ages(“leo”)
使用contains函數檢查key是否存在:
val leoAge = if (ages.contains(“leo”)) ages(“leo”) else 0
getOrElse函數:
val leoAge = ages.getOrElse(“leo”, 0)
(3)修改Map的元素
更新Map的元素:
ages(“Leo”) = 31
增加多個元素:
ages += (“Mike” -> 35, “Tom” -> 40)
移除元素:
ages -= “Mike”
更新不可變的map:
val ages2 = ages + (“Mike” -> 36, “Tom” -> 40)
移除不可變map的元素:
val ages3 = ages - “Tom”
(4)遍歷Map
遍歷map的entrySet:
for ((key, value) <- ages) println(key + ” ” + value)
遍歷map的key:
for (key <- ages.keySet) println(key)
遍歷map的value:
for (value <- ages.values) println(value)
生成新map,反轉key和value:
for ((key, value) <- ages) yield (value, key)
(5)SortedMap和LinkedHashMap
SortedMap可以自動對Map的key的排序:
val ages = scala.collection.immutable.SortedMap(“leo” -> 30, “alice” -> 15, “jen” -> 25)
LinkedHashMap可以記住插入entry的順序:
val ages = new scala.collection.mutable.LinkedHashMap[String, Int]
ages(“leo”) = 30
ages(“alice”) = 15
ages(“jen”) = 25
(6)Map的元素類型—Tuple
Map的每一個元素(key,value)就稱作:tuple元組對
簡單的Tuple定義:
val t = (“leo”, 30)
訪問Tuple:
t._1
zip拉鏈操作:
val names = Array(“leo”, “jack”, “mike”)
val ages = Array(30, 24, 26)
val nameAges = names.zip(ages)
for ((name, age) <- nameAges) println(name + “: ” + age)
4、數組Array
在Scala中,Array代表的含義與Java中類似,也是長度不可改變的數組。此外,由於Scala與Java都是運行在JVM中,雙方可以互相調用,因此Scala數組的底層實際上是Java數組。例如字符串數組在底層就是Java的String[],整數數組在底層就是Java的Int[]。
(1)數組初始化后,長度就固定下來了,而且元素全部根據其類型初始化
val a = new ArrayInt
a(0)
a(0) = 1
val a = new ArrayString
(2)可以直接使用Array()創建數組,元素類型自動推斷
val a = Array(“hello”, “world”)
a(0) = “hi”
val a = Array(“leo”, 30)
(3)數組元素求和
val a = Array(1, 2, 3, 4, 5)
val sum = a.sum
(4)獲取數組最大值
val max = a.max
(5)對數組進行排序
scala.util.Sorting.quickSort(a)
(6)獲取數組中所有元素內容
a.mkString
a.mkString(“, “)
a.mkString(“<”, “,”, “>”)
(7)toString函數
a.toString
5、數組ArrayBuffer
在Scala中,如果需要類似於Java中的ArrayList這種長度可變的集合類,則可以使用ArrayBuffer。
(1)如果不想每次都使用全限定名,則可以預先導入ArrayBuffer類
import scala.collection.mutable.ArrayBuffer
(2)使用ArrayBuffer()的方式可以創建一個空的ArrayBuffer
val b = ArrayBufferInt
(3)使用+=操作符,可以添加一個元素,或者多個元素。這個語法必須要謹記在心!因為spark源碼里大量使用了這種集合操作語法!
b += 1
b += (2, 3, 4, 5)
(4)使用++=操作符,可以添加其他集合中的所有元素
b ++= Array(6, 7, 8, 9, 10)
(5)使用trimEnd()函數,可以從尾部截斷指定個數的元素
b.trimEnd(5)
(6)使用insert()函數可以在指定位置插入元素,但是這種操作效率很低,因為需要移動指定位置后的所有元素。
b.insert(5, 6)
b.insert(6, 7, 8, 9, 10)
(7)使用remove()函數可以移除指定位置的元素
b.remove(1)
b.remove(1, 3)
(8)Array與ArrayBuffer可以互相進行轉換
b.toArray
a.toBuffer
(9)使用for循環和until遍歷Array / ArrayBuffer
until是RichInt提供的函數
for (i <- 0 until b.length)
println(b(i))
(10)跳躍遍歷Array / ArrayBuffer
for(i <- 0 until (b.length, 2))
println(b(i))
(11)從尾部遍歷Array / ArrayBuffer
for(i <- (0 until b.length).reverse)
println(b(i))
(12)使用“增強for循環”遍歷Array / ArrayBuffer
for (e <- b)
println(e)
(13)toString函數
b.toString
6、數組操作
(1)使用yield和函數式編程轉換數組
對Array進行轉換,獲取的還是Array
val a = Array(1, 2, 3, 4, 5)
val a2 = for (ele <- a) yield ele * ele
對ArrayBuffer進行轉換,獲取的還是ArrayBuffer
val b = ArrayBufferInt
b += (1, 2, 3, 4, 5)
val b2 = for (ele <- b) yield ele * ele
結合if守衛,僅轉換需要的元素
val a3 = for (ele <- if ele % 2 == 0) yield ele * ele
(2)使用函數式編程轉換數組(通常使用第一種方式)
a.filter(_ % 2 == 0).map(2 * _)
a.filter { _ % 2 == 0 } map { 2 * _ }
(3)算法案例:移除第一個負數之后的所有負數
- 算法一:
構建數組:
val a = ArrayBufferInt
a += (1, 2, 3, 4, 5, -1, -3, -5, -9)
每發現一個第一個負數之后的負數,就進行移除,性能較差,多次移動數組:
var foundFirstNegative = false
var arrayLength = a.length
var index = 0
while (index < arrayLength) {
if (a(index) >= 0) {
index += 1
} else {
if (!foundFirstNegative) { foundFirstNegative = true; index += 1 }
else { a.remove(index); arrayLength -= 1 }
}
}
2. 算法二:
重新構建數組:
val a = ArrayBufferInt
a += (1, 2, 3, 4, 5, -1, -3, -5, -9)
每記錄所有不需要移除的元素的索引,稍后一次性移除所有需要移除的元素。該算法性能較高,數組內的元素遷移只要執行一次即可。
var foundFirstNegative = false
val keepIndexes = for (i <- 0 until a.length if !foundFirstNegative || a(i) >= 0) yield {
if (a(i) < 0) foundFirstNegative = true
i
}
for (i <- 0 until keepIndexes.length) { a(i) = a(keepIndexes(i)) }
a.trimEnd(a.length - keepIndexes.length)