1、數據結構特點
Scala同時支持可變集合和不可變集合,不可變集合從不可變,可以安全的並發訪問。
兩個主要的包:
不可變集合:scala.collection.immutable
可變集合: scala.collection.mutable
Scala優先采用不可變集合,對於幾乎所有的集合類,Scala都同時提供了可變和不可變的版本。
不可變集合繼承層次:
可變集合繼承層次:
2、數組
2.1、定義定長數組
我們可以定義一個固定長度大小和類型的定長數組
//定義一個數組長度為10,類型為Int的固定大小數組 val array = new Array[Int](10) array(1) = 10 array(2) = 20 //訪問數組當中的某一個下標元素值 println(array(1)) //直接使用apply方法進行生成一個數組 val array2 = Array(1,2,3) //訪問數組的元素 println(array2(2)) |
|
2.2、變長數組
我們也可以通過ArrayBuffer來定義一個變長數組
val array3 = new ArrayBuffer[Int]() array3.append(20) val array4 = ArrayBuffer[String]() array4.append("helloworld") |
2.3、定長數組與變長數組的相互轉換
//定長數組轉換成變長數組 val toBuffer = array.toBuffer toBuffer.append(50) //變長數組准換成定長數組 val toArray = array3.toArray |
2.4、多維數組
我們可以通過Array的ofDim方法來定義一個多維的數組,多少行,多少列,都是我們自己定義說了算
val dim = Array.ofDim[Double](3,4) dim(1)(1) = 11.11 println(dim.mkString(",")) |
2.5、scala當中數組的遍歷
val array5 = ArrayBuffer(1,2,3,4,5,6) for(x <- array5){ println(x ) } |
2.6、數組的常見算法
val array6 = Array(1,2,3,4,5,6) //求和 array6.sum //求最大值 array6.max //排序 array6.sorted |
3、元組tuple
在scala當中提供元組tuple的數據類型,可以理解tuple為一個容器,可以存放各種不同的數據類型的數據,例如一個Tuple當中既可以存放String類型數據,同時也可以存放Int類型的數據
注意:注意元組一旦創建之后,就是不可變的,也就是說元組當中沒有添加和刪除元素這一說
3.1、創建元組
創建元組,直接使用小括號,小括號當中存放我們元組當中各種類型的元素即可
val tuple1 = ("hello",1,5.0f) println(tuple1) |
3.2、元組數據的訪問
訪問元組當中的數據直接使用_加角標即可,但是要注意,元組當中的數據角標是從1開始的
val tuple1 = ("hello",1,5.0f) println(tuple1)
val tuple1Result = tuple1._1 println(tuple1Result) |
3.3、元組的遍歷
val tuple1 = ("hello",1,5.0f) println(tuple1)
val tuple1Result = tuple1._1 println(tuple1Result) |
//第一種方式遍歷元組
for(x <- tuple1.productIterator){ println(x) } //第二種方式遍歷元組 tuple1.productIterator.foreach( x => println(x)) |
4、映射Map
scala當中的Map集合與java當中的Map類似,也是key,value對形式的
4.1、不可變映射
val map1 = Map("hello" ->"world","name" -> "zhangsan","age" -> 18) |
4.2、可變映射及其操作
val map2 = scala.collection.mutable.Map("hello" ->"world","name" -> "zhangsan","age" -> 18) //可變map添加元素 map2.+=("address" ->"地球") println(map2) //可變map刪除元素.注意,刪除元素是返回一個刪除元素之后的map,原來的map並沒有改變 val map3 = map2.-("address") println(map2) println(map3)
//可變map更新元素 map2("address") ="火星" println(map2) //或者使用覆蓋key的方式來更細元素 map2 += ("address" -> "北京") println(map2) //或者使用 + 來進行更新元素 //注意,map當中沒有phonNo這個key,則不能更細 map2 +("address" ->"上海","phonNo" -> "13688886666") println(map2) |
4.3、獲取map當中指定的key值
//通過key來進行取值 map2.get("address") //通過key來進行取值,如果沒有這個key,就用后面給定的默認值 map2.getOrElse("address","非洲") //通過key來進行取值,真的沒有這個key,那么就用后面給定的默認值 map2.getOrElse("phoNo","13133335555") |
4.4、遍歷Map當中的元素
//遍歷key與value for((k,v) <- map2){ println(k) println(v) }
//遍歷獲取所有的key for(k <- map2.keys) { println(k) } //遍歷獲取所有的value for(v <- map2.values) { println(v) }
//打印key,value對 for(kv <- map2){ println(kv) } |
4.5、將對偶的數組轉變為map
//將對偶的元組轉變為map val arrayMap = Array(("name","zhangsan"),("age",28)) val toMap = arrayMap.toMap println(toMap) |
5、列表(List)
scala當中也提供有與java類似的List集合操作
5.1、創建列表
注意:列表當中的元素類型可以是不同的,這一點與我們元組類似,但是列表當中的元素是可以刪減的
val list1 = List("hello",20,5.0f) println(list1) |
5.2、訪問列表當中的元素
//訪問列表當中的元素 val list1Result = list1(0) println(list1Result) |
5.3、列表當中添加元素
我們可以從列表頭部或者尾部添加元素
val list2 = list1:+50 val list3 = 100+:list1 println(list2) println(list3) |
5.4、List的創建與追加元素
Nil是一個空的List,定義為List[Nothing]
//尾部添加了Nil,那么就會出現List集合里面裝List集合的現象 val list4 = 1::2 ::3 :: list1 ::Nil println(list4) //尾部沒有添加Nil的值,那么所有的元素都壓平到一個集合里面去了 val list5 = 1::2::3::list1 println(list5) |
5.5、變長List的創建與使用
val list6 = new ListBuffer[String] list6.append("hello") list6.append("world") println(list6.mkString(",")) val list7 = list6.toList println(list7) |
5.6、List操作延伸閱讀
Scala是函數式風格與面向對象共存的編程語言,方法不應該有副作用是函數風格編程的一個重要的理念。方法唯一的效果應該是計算並返回值,用這種方式工作的好處就是方法之間很少糾纏在一起,因此就更加可靠和可重用。另一個好處(靜態類型語言)是傳入傳出方法的所有東西都被類型檢查器檢查,因此邏輯錯誤會更有可能把自己表現為類型錯誤。把這個函數式編程的哲學應用到對象世界里以為着使對象不可變。
前面一章介紹的Array數組是一個所有對象都共享相同類型的可變序列。比方說Array[String]僅包含String。盡管實例化之后你無法改變Array的長度。因此,Array是可變的對象。
說到共享相同類型的不可變對象類型,Scala的List類才是。和數組一樣,List[String]包含的僅僅是String。Scala的List不同於Java的java.util.List,總是不可變的(Java的List是可變)。更准確的說法,Scala的List是設計給函數式風格的編程用的。
(1)List類型定義以及List的特點:
//字符串類型List scala> val fruit=List("Apple","Banana","Orange") fruit: List[String] = List(Apple, Banana, Orange) //前一個語句與下面語句等同 scala> val fruit=List.apply("Apple","Banana","Orange") fruit: List[String] = List(Apple, Banana, Orange) //數值類型List scala> val nums=List(1,2,3,4,5) nums: List[Int] = List(1, 2, 3, 4, 5) //多重List,List的子元素為List scala> val list = List(List(1, 2, 3), List("adfa", "asdfa", "asdf")) list: List[List[Any]] = List(List(1, 2, 3), List(adfa, asdfa, asdf))
//遍歷List scala> for(i <- list; from=i; j<-from)println(j) 1 2 3 adfa asdfa asdf |
(2)List與Array的區別:
1、List一旦創建,已有元素的值不能改變,可以使用添加元素或刪除元素生成一個新的集合返回。
如前面的nums,改變其值的話,編譯器就會報錯。而Array就可以成功
scala>nums(3)=4 <console>:10: error: value update is not a member of List[Int] nums(3)=4 ^ |
2、List具有遞歸結構(Recursive Structure),例如鏈表結構
List類型和氣他類型集合一樣,它具有協變性(Covariant),即對於類型S和T,如果S是T的子類型,則List[S]也是List[T]的子類型。
例如:
scala>var listStr:List[Object] = List("This", "Is", "Covariant", "Example") listStr:List[Object] = List(This, Is, Covariant, Example)
//空的List,其類行為Nothing,Nothing在Scala的繼承層次中的最底層 //,即Nothing是任何Scala其它類型如String,Object等的子類 scala> var listStr = List() listStr:List[Nothing] = List()
scala>var listStr:List[String] = List() listStr:List[String] = List() |
(3)List常用構造方法
//1、常用::及Nil進行列表構建 scala> val nums = 1 :: (2:: (3:: (4 :: Nil))) nums: List[Int] = List(1, 2, 3, 4) //由於::操作符的優先級是從右向左的,因此上一條語句等同於下面這條語句 scala> val nums = 1::2::3::4::Nil nums:List[Int] = List(1, 2, 3, 4) |
至於::操作符的使用將在下面介紹
(4)List常用操作
//判斷是否為空 scala> nums.isEmpty res5: Boolean = false //取第一個元素 scala> nums.head res6: Int = 1 //取列表第二個元素 scala>nums.tail.head res7: Int = 2
//取第三個元素 scala>nums.tail.tail.head res8: Int = 3
//插入操作 //在第二個位置插入一個元素 scala>nums.head::(3::nums.tail) res11: List[Int] = List(1, 3, 2, 3, 4)
scala> nums.head::(nums.tail.head::(4::nums.tail.tail)) res12: List[Int] = List(1, 2, 4, 3, 4)
//插入排序算法實現 def isort(xs: List[Int]):List[Int] = { if(xs.isEmpty) Nil else insert(xs.head, issort(xs.tail)) }
def insert(x:Int, xs:List[Int]):List[Int] = { if(xs.isEmpty || x <= xs.head) x::xs else xs.head :: insert(x, xs.tail) }
//連接操作 scala>List(1, 2, 3):::List(4, 5, 6) res13: List[Int] = List(1, 2, 3, 4, 5, 6)
//去除最后一個元素外的元素,返回的是列表 scala> nums.init res13: List[Int] = List(1, 2, 3)
//取出列表最后一個元素 scala>nums.last res14: Int = 4
//列表元素倒置 scala> nums.reverse res15: List[Int] = List(4, 3, 2, 1) //一些好玩的方法調用 scala> nums.reverse.reverse == nums //丟棄前面n個元素 scala>nums drop 3 res16: List[Int] = List(4) //獲取前面n個元素 scala>nums take 1 res17: List[Int] = List[1] //將列表進行分割 scala> nums.splitAt(2) res18: (List[Int], List[Int]) = (List(1, 2),List(3, 4)) //前一個操作與下列語句等同 scala> (nums.take(2),nums.drop(2)) res19: (List[Int], List[Int]) = (List(1, 2),List(3, 4)) //Zip操作 scala> val nums=List(1,2,3,4) nums: List[Int] = List(1, 2, 3, 4) scala> val chars=List('1','2','3','4') chars: List[Char] = List(1, 2, 3, 4) //返回的是List類型的元組(Tuple),返回的元素個數與最小的List集合的元素個數一樣 scala> nums zip chars res20: List[(Int, Char)] = List((1,1), (2,2), (3,3), (4,4))
//List toString方法 scala> nums.toString res21: String = List(1, 2, 3, 4)
//List mkString方法 scala> nums.mkString res22: String = 1234
//轉換成數組 scala> nums.toArray res23: Array[Int] = Array(1, 2, 3, 4) |
(5)List伴生對象方法
//apply方法 scala> List.apply(1, 2, 3) res24: List[Int] = List(1, 2, 3) //range方法,構建某一值范圍內的List scala> List.range(2, 6) res25: List[Int] = List(2, 3, 4, 5) //步長為2 scala> List.range(2, 6,2) res26: List[Int] = List(2, 4) //步長為-1 scala> List.range(2, 6,-1) res27: List[Int] = List() scala> List.range(6,2 ,-1) res28: List[Int] = List(6, 5, 4, 3) //構建相同元素的List scala> List.make(5, "hey") res29: List[String] = List(hey, hey, hey, hey, hey)
//unzip方法 scala> List.unzip(res20) res30: (List[Int], List[Char]) = (List(1, 2, 3, 4),List(1, 2, 3, 4))
//list.flatten,將列表平滑成第一個無素 scala> val xss =List(List('a', 'b'), List('c'), List('d', 'e')) xss: List[List[Char]] = List(List(a, b), List(c), List(d, e)) scala> xss.flatten res31: List[Char] = List(a, b, c, d, e)
//列表連接 scala> List.concat(List('a', 'b'), List('c')) res32: List[Char] = List(a, b, c) |
(6)::和:::操作符介紹
List中常用'::',發音為"cons"。Cons把一個新元素組合到已有元素的最前端,然后返回結果List。
scala> val twoThree = List(2, 3) scala> val oneTwoThree = 1 :: twoThree scala> oneTwoThree oneTwoThree: List[Int] = List(1, 2, 3) |
上面表達式"1::twoThree"中,::是右操作數,列表twoThree的方法。可能會有疑惑。表達式怎么是右邊參數的方法,這是Scala語言的一個例外的情況:如果一個方法操作符標注,如a * b,那么方法被左操作數調用,就像a.* (b)--除非方法名以冒號結尾。這種情況下,方法被右操作數調用。
List有個方法叫":::",用於實現疊加兩個列表。
scala> val one = List('A', 'B') val one = List('A', 'B') scala> val two = List('C', 'D') scala> one:::two res1: List[Char] = List(A, B, C, D) |
6、Set集合
集是不重復元素的結合。集不保留順序,默認是以哈希集實現。
如果想要按照已排序的順序來訪問集中的元素,可以使用SortedSet(已排序數據集),已排序的數據集是用紅黑樹實現的。
默認情況下,Scala 使用的是不可變集合,如果你想使用可變集合,需要引用 scala.collection.mutable.Set 包。
6.1、不可變集合的創建
val set1 =Set("1","1","2","3") println(set1.mkString(",")) |
6.2、可變集合的創建以及添加元素
如果我們引入的集合的包是可變的,那么我們創建的集合就是可變的
import scala.collection.mutable.Set val set2 = Set(1, 2, 3) set2.add(4) set2 += 5 //使用.這個方法添加元素,會返回一個新的集合 val set3 = set2.+(6) println(set2.mkString(",")) println(set3.mkString("\001")) |
6.3、可變集合刪除元素
set3 -= 1 println(set3.mkString("."))
set3.remove(2) println(set3.mkString(".")) |
6.4、遍歷Set集合元素
for(x <- set3){ println(x ) } |
注意:如果要創建有序的set,那么需要使用SortedSet。用法與Set類似
更多Set集合操作參見如下:
http://www.runoob.com/scala/scala-sets.html
6.5、Set更多常用操作介紹
序號 |
方法 |
描述 |
1 |
def +(elem: A): Set[A] |
為集合添加新元素,並創建一個新的集合,除非元素已存在 |
2 |
def -(elem: A): Set[A] |
移除集合中的元素,並創建一個新的集合 |
3 |
def contains(elem: A): Boolean |
如果元素在集合中存在,返回 true,否則返回 false。 |
4 |
def &(that: Set[A]): Set[A] |
返回兩個集合的交集 |
5 |
def &~(that: Set[A]): Set[A] |
返回兩個集合的差集 |
6 |
def ++(elems: A): Set[A] |
合並兩個集合 |
7 |
def drop(n: Int): Set[A]] |
返回丟棄前n個元素新集合 |
8 |
def dropRight(n: Int): Set[A] |
返回丟棄最后n個元素新集合 |
9 |
def dropWhile(p: (A) => Boolean): Set[A] |
從左向右丟棄元素,直到條件p不成立 |
10 |
def max: A |
查找最大元素 |
11 |
def min: A |
查找最小元素 |
12 |
def take(n: Int): Set[A] |
返回前 n 個元素 |
7、集合元素與函數的映射
我們可以使用map方法,傳入一個函數,然后將這個函數作用在集合當中的每一個元素上面
map:將集合中的每一個元素映射到某一個函數
val listFunc = List("name","age","zhangsan","lisi") println(listFunc.map(x => x +"hello")) println(listFunc.map(_.toUpperCase())) |
flatmap:flat即壓扁,壓平,扁平化,效果就是將集合中的每個元素的子元素映射到某個函數並返回新的集合
val listFunc2 = List("address","phonNo") println(listFunc2.flatMap( x => x +"WORLD")) |
8、隊列Queue
隊列Queue是一個先進先出的結構
8.1、創建隊列
//創建可變的隊列 val queue1 = new mutable.Queue[Int]() println(queue1) |
8.2、隊列當中添加元素
//隊列當中添加元素 queue1 += 1 //隊列當中添加List queue1 ++=List(2,3,4) println(queue1) |
8.3、按照進入隊列順序,刪除隊列當中的元素(彈出隊列)
val dequeue = queue1.dequeue() println(dequeue) println(queue1) |
8.4、向隊列當中加入元素(入隊列操作)
//塞入元素到隊列 queue1.enqueue(5,6,7) println(queue1) |
8.5、獲取第一個與最后一個元素
//獲取第一個元素 println(queue1.head) //獲取最后一個元素 println(queue1.last) |
9、集合當中的化簡、折疊與掃描操作
9.1、折疊、化簡 reduce操作
將二元函數引用集合當中的函數
val reduceList = List(1,2,3,4,5) //1-2-3-4-5 = -13 val reduceLeftList = reduceList.reduceLeft(_ - _) val reduceLeftList2 = reduceList.reduceLeft((x,y) => x-y) println(reduceLeftList) println(reduceLeftList2) //reduceRight操作 // 4-5 = -1 // 3- (-1) = 4 //2-4 = -2 //1 -(-2) = 3 val reduceRightList = reduceList.reduceRight(_ - _) println(reduceRightList) |
9.2、折疊、化簡folder操作
fold函數將上一步返回的值作為函數的第一個參數繼續傳遞參與運算,直到list中的所有元素被遍歷。可以把reduceLeft看做簡化版的foldLeft。相關函數:fold,foldLeft,foldRight,可以參考reduce的相關方法理解。
reduce的本質其實就是fold操作,只不過我們使用fold操作的時候,需要指定初始值fold操作
val foldList = List(1,9,2,8) val foldResult = foldList.fold(10)((x,y) => x+y) println(foldResult)
foldLeft操作
//50-1-9-2-8 = 30 val foldLeftResult = foldList.foldLeft(50)((x,y) => x-y) println(foldLeftResult) |
10、拉鏈操作
對於多個List集合,我們可以使用Zip操作,將多個集合當中的值綁定到一起去
val zipList1 = List("name","age","sex") val zipList2 = List("zhangsan",28) val zip = zipList1.zip(zipList2) val toMap1 = zip.toMap println(zip) println(toMap1) |
11、迭代器
對於集合當中的元素,我們也可以使用迭代器來進行遍歷
val listIterator = List(1,2,"zhangsan") val iterator = listIterator.iterator while(iterator.hasNext){ println(iterator.next()) } |
12、線程安全的集合
scala當中為了解決多線程並發的問題,提供對應的線程安全的集合
https://www.scala-lang.org/api/2.11.8/#package
SynchronizedBuffer
SynchronizedMap
SynchronizedPriorityQueue
SynchronizedQueue
SynchronizedSet
13、操作符
大致了解即可
-
如果想在變量名、類名等定義中使用語法關鍵字(保留字),可以配合反引號反引號:
var `var` num:Int = 2
2) 這種形式叫中置操作符,A操作符B等同於A.操作符(B)
3) 后置操作符,A操作符等同於A.操作符,如果操作符定義的時候不帶()則調用時不能加括號
4) 前置操作符,+、-、!、~等操作符A等同於A.unary_操作符。
5) 賦值操作符,A操作符=B等同於A=A操作符B