[轉] Scala 的集合類型與數組操做

[From] https://blog.csdn.net/gongxifacai_believe/article/details/81916659html

 

 

版權聲明:本文爲博主原創文章,轉載請註明出處。 https://blog.csdn.net/gongxifacai_believe/article/details/81916659

一、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
全部集合組件圖示以下:
算法

 

二、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集合。api

val list2 = 1::Nil

注意集合的順序,前面是元素後面是集合數組

val list3 = 2::list2

前面的元素就是新的list的head,後面的就是新的list的tail
(3)建立一個可變的list集合markdown

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集合建立
不可變集合:post

val set = Set(1,2,3,4)

可變集合:性能

val s = scala.collection.mutable.Set(1,2)

添加元素:
不可變集合:+ ++ - –
可變集合:+= ++= -= --=

 

三、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)

 

四、數組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

 

五、數組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

 

六、數組操做

(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)算法案例:移除第一個負數以後的全部負數

  1.   算法一:
    構建數組:
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)
相關文章
相關標籤/搜索