1. 集合简介
- Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable特质
- 对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包
不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable - Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而
不会对原对象进行修改。类似于 java 中的 String 对象 - 可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象
在操作集合的时候,不可变用符号,可变用方法
1.1. 不可变集合继承图
- Set、Map 是 Java 中也有的集合
- Seq 是 Java 没有的,我们发现 List 归属到 Seq 了,因此这里的 List 就和 Java 不是同一个概念了
- 我们前面的 for 循环有一个 1 to 3,就是 IndexedSeq 下的 Range
- String 也是属于 IndexedSeq
- 我们发现经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列) 6)大家注意 Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序
- IndexedSeq 和 LinearSeq 的区别:IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集合,通过索引即可定位;LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
7.2. 可变集合继承图
2. 数组
2.1. 不可变数组
2.1.1. 第一种方式定义数组
定义:val arr1 = new Array[Int] (10)
- new 是关键字
- [Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定 Any
- 10),表示数组的大小,确定后就不可以变化
package com.michael.learn.day04
object TestArray {
def main(args: Array[String]): Unit = {
// 1. declare an array
val arr01 = new Array[Int](4)
println(arr01.length) // 4
// 2. Array assignment
arr01(3) = 10
arr01.update(0, 9)
// 3. through the array
// 3.1. check the array
println(arr01.mkString(",")) // 9,0,0,10
// 3.2. for loop
for(i <- arr01){print(i+" ")} // 9 0 0 10
println()
// 3.3. simplify through
def printx(ele:Int):Unit = {print(ele+" ")}
arr01.foreach(printx) // 9 0 0 10
println()
arr01.foreach((x) => print(x + " ")) // 9 0 0 10
println()
// 4. add an element (create a new array)
println(arr01.length)
val ints:Array[Int] = arr01 :+ 5
ints.foreach(printx)
}
}
2.1.2. 第二种方式定义数组
val arr1 = Array(1, 2)
- 在定义数组时,直接赋初始值
- 使用 apply 方法创建数组对象
package com.michael.learn.day04
object TestArray02 {
def main(args: Array[String]): Unit = {
var array02 = Array(1, 3, "michael")
println(array02.length) // 3
for(i <- array02) print(i + " ") // 1 3 michael
}
}
2.2. 可变数组
val arr01 = ArrayBuffer[Any] (3, 2, 5)
- [Any]存放任意数据类型
- (3, 2, 5)初始化好的三个元素
- ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer
package com.michael.learn.day04
import scala.collection.mutable.ArrayBuffer
object TestArrayBuffer {
def main(args: Array[String]): Unit = {
// 1. create an array and initial it
val array03 = ArrayBuffer[Any](1, 2, 3)
// 2. through the array
for (i <- array03) print(i + " ") // 1 2 3
println()
// 3. add new elements
// 3.1. append element
array03.+=(4)
println(array03.mkString(" ")) // 1 2 3 4
// 3.2. append elements at the end of the array
array03.append(5, 6)
println(array03.mkString(" ")) // 1 2 3 4 5 6
// 3.3. insert elements at the appointed index
array03.insert(0, 7, 8, 9)
println(array03.mkString(" ")) // 7 8 9 1 2 3 4 5 6
// 4. update element
array03(1) = 9
println(array03.mkString(" ")) // 7 9 9 1 2 3 4 5 6
println(array03.length) // 9
}
}
2.3. 可变数组与不可变数组的转换
arr1.toBuffer // 不可变数组转可变数组; arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化
arr2.toArray // 可变数组转不可变数组;arr1.toBuffer 返回结果才是一个可变数组,arr1 本身没有变化
package com.michael.learn.day04
import scala.collection.mutable.ArrayBuffer
object TestArrayBuffer2 {
def main(args: Array[String]): Unit = {
// 1. create an Array
val array04 = ArrayBuffer[Int]()
// 2. append some elements
array04.append(1, 2, 3)
println(array04) // ArrayBuffer(1, 2, 3)
// 3. ArrayBuffer ==> Array
val newArr = array04.toArray
println(newArr.mkString(",")) // 1,2,3
// 4. Array ==> ArrayBuffer
val newArrBuffer = newArr.toBuffer
println(newArrBuffer) // ArrayBuffer(1, 2, 3)
newArrBuffer.append(123)
println(newArrBuffer) // ArrayBuffer(1, 2, 3, 123)
}
}
2.4. 多维数组
val arr = Array.ofDimDouble
说明:二维数组中有三个一维数组,每个一维数组中有四个元素
package com.michael.learn.day04
object TestDimArray {
def main(args: Array[String]): Unit = {
// 1. create a 2d array
val arr = Array.ofDim[Int](3, 4)
arr(1)(2) = 12
arr(2)(3) = 23
// 2. through the array
for (i <- arr){
for (j <- i){
print(j+" ")
}
println()
}
// 0 0 0 0
// 0 0 12 0
// 0 0 0 23
}
}
3. 列表List
3.1. 不可变List
- List 默认为不可变集合
- 创建一个 List(数据有顺序,可重复)
- 遍历 List
- List 增加数据
- 集合间合并:将一个整体拆成一个一个的个体,称为扁平化
- 取指定数据
- 空集合 Nil
package com.michael.learn.day04
object TestList {
def main(args: Array[String]): Unit = {
// 1. create a new list
val list:List[Int] = List(1, 2, 3, 4)
println(list) // List(1, 2, 3, 4)
val list10 = 1::2::3::4::Nil
println(list10) // List(1, 2, 3, 4)
// 2. add elements
val list1 = 5::list
println(list1) // List(5, 1, 2, 3, 4)
val list11 = 7::6::5::list
println(list11) // List(7, 6, 5, 1, 2, 3, 4)
val list2 = list.+:(5)
println(list2) // List(5, 1, 2, 3, 4)
// 3. merge lists
val list3 = List(8, 9)
val list4 = list3:::list1
println(list4) // List(8, 9, 5, 1, 2, 3, 4)
// 4. get value from list with appointed index
println(list(1)) // 2
// 5. though the list
list.foreach(print) // 1234
}
}
3.2. 可变ListBuffer
- 创建一个可变集合 ListBuffer
- 向集合中添加数据
- 打印集合数据
package com.michael.learn.day04
import scala.collection.mutable.ListBuffer
object TestListBuffer {
def main(args: Array[String]): Unit = {
// 1. create a new list
val listBuffer = ListBuffer(1,2,3,4)
// 2. add elements
listBuffer.+=(5)
listBuffer.append(6, 7)
listBuffer.insert(7, 8)
// 3. though the list
listBuffer.foreach((x) => print(x+" ")) // 1 2 3 4 5 6 7 8
println()
// 4. update value based on index
listBuffer(1) = 12
listBuffer.update(0, 11)
println(listBuffer) // ListBuffer(11, 12, 3, 4, 5, 6, 7, 8)
// 5. delete element
listBuffer.-(5)
println(listBuffer) // ListBuffer(11, 12, 3, 4, 5, 6, 7, 8)
listBuffer.-=(12)
println(listBuffer) // ListBuffer(11, 3, 4, 5, 6, 7, 8)
listBuffer.remove(5)
println(listBuffer) // ListBuffer(11, 3, 4, 5, 6, 8)
}
}
4. Set集合
Scala 使用的是不可变集合,如果你想使用可变集合,需要引用scala.collection.mutable.Set 包
4.1. 不可变Set
- Set 默认是不可变集合,数据无序
- 数据不可重复
- 遍历集合
package com.michael.learn.day04
object TestSet {
def main(args: Array[String]): Unit = {
// 1. create a set (data is unordered)
val set = Set(1,2,3,4,5,6)
println(set) // Set(5, 1, 6, 2, 3, 4)
// 2. data is unrepeated
val set1 = Set(1,2,3,4,5,6,3)
println(set1) // Set(5, 1, 6, 2, 3, 4)
// 3. though the set
for(i <- set) print(i + " ") // 5 1 6 2 3 4
}
}
4.2. 可变mutable.Set
- 创建可变集合 mutable.Set
- 打印集合
- 集合添加元素
- 向集合中添加元素,返回一个新的 Set
- 删除数据
package com.michael.learn.day04
import scala.collection.mutable
object TestmutableSet {
def main(args: Array[String]): Unit = {
// 1. create a set
val set = mutable.Set(1,2,3,4,5,6)
println(set) // Set(1, 5, 2, 6, 3, 4)
// 2. add element
set += 7
println(set) // Set(1, 5, 2, 6, 3, 7, 4)
// 3. add an element to create a new set
val ints = set.+(8)
println(ints) // Set(1, 5, 2, 6, 3, 7, 4, 8)
// 4. delete value
set -= 5
println(set) // Set(1, 2, 6, 3, 7, 4)
// 6. though the set
set.foreach(x => print(x+",")) // 1,2,6,3,7,4,
println()
println(set.mkString(",")) // 1,2,6,3,7,4
}
}
5. Map集合
Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value)映射
5.1. 不可变Map
- 创建不可变集合 Map
- 循环打印
- 访问数据
- 如果 key 不存在,返回 0
package com.michael.learn.day04
object TestMap {
def main(args: Array[String]): Unit = {
// 1. create a map
val map = Map( "a"->1, "b"->2, "c"->3)
println(map) // Map(a -> 1, b -> 2, c -> 3)
// 2. get value
for(ele <- map.keys) print(ele+"="+map.get(ele).get+" ") // a=1 b=2 c=3
println()
// 3. return 0 if the key does not exist
println(map.get("d").getOrElse(0)) // 0
println(map.getOrElse("d", 0)) // 0
// 4. though the map
map.foreach((kv) => print(kv+" ")) // (a,1) (b,2) (c,3)
}
}
5.2. 可变Map
- 创建可变集合
- 打印集合
- 向集合增加数据
- 删除数据
- 修改数据
package com.michael.learn.day04
import scala.collection.mutable
object TestMutableMap {
def main(args: Array[String]): Unit = {
// 1. create a map
val map = mutable.Map( "a"->1, "b"->2, "c"->3)
// 2. add a new element
map.+=("d"->4)
println(map) // Map(b -> 2, d -> 4, a -> 1, c -> 3)
// 3. put 4 into map and get the original value of key a
val maybeInt:Option[Int] = map.put("a", 4)
println(map) // Map(b -> 2, d -> 4, a -> 4, c -> 3)
println(maybeInt.getOrElse(0)) // 1
// 4. delete value
map.-=("b", "c")
println(map) // Map(d -> 4, a -> 4)
// 5. update value
map.update("d", 55)
println(map) // Map(d -> 55, a -> 4)
// 6. though map
map.foreach((kv) => print(kv + " ")) // (d,55) (a,4)
}
}
6. 元祖
元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组
注意:元组中最大只能有 22 个元素
package com.michael.learn.day04
object TestTuple {
def main(args: Array[String]): Unit = {
// 1. create a tuple
val tuple:(Int, String, Boolean) = (100, "michael", true)
println(tuple) // (100,michael,true)
// 2. get values from tuple
// 2.1. by symbol _
println(tuple._1) // 100
// 2.2. by index
println(tuple.productElement(1)) // michael
// 2.3. by iterator
for (ele <- tuple.productIterator){print(ele+" ")} // 100 michael true
println()
// 3. Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为对偶
val map1 = Map("a"->1, "b"->2, "c"->3)
val map2 = Map(("a",1), ("b",2), ("c",3))
map1.foreach(tuple=>{print(tuple._1 + "=" + tuple._2 + " ")}) // a=1 b=2 c=3
println()
map2.foreach(tuple=>{print(tuple._1 + "=" + tuple._2 + " ")}) // a=1 b=2 c=3
}
}
7. 集合常用函数
7.1. 基本属性和常用操作
- 获取集合长度
- 获取集合大小
- 循环遍历
- 迭代器
- 生成字符串
- 是否包含
package com.michael.learn.day04
object TestList2 {
def main(args: Array[String]): Unit = {
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
// 1. get the length
println(list.length) // 7
// 2. get the size
println(list.size) // 7 same as length
// 3. though the list by for each
list.foreach(print) // 1234567
println()
// 4. though the list by iterator
for(ele <- list.iterator){print(ele)} // 1234567
println()
// 5. to string
println(list.mkString(",")) // 1,2,3,4,5,6,7
// 6. if contains
println(list.contains(9)) // false
}
}
7.2. 衍生集合
- 获取集合的头
- 获取集合的尾(不是头的就是尾)
- 集合最后一个数据
- 集合初始数据(不包含最后一个)
- 反转
- 取前(后)n 个元素
- 去掉前(后)n 个元素
- 并集
- 交集
- 差集
- 拉链
- 滑窗
package com.michael.learn.day04
object TestList3 {
def main(args: Array[String]): Unit = {
val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
val list2: List[Int] = List(4, 5, 6, 7, 8, 9, 10)
// 1. get the head
println(list1.head) // 1
// 2. get the tail (it's either head or tail)
println(list1.tail) // List(2, 3, 4, 5, 6, 7)
// 3. get the last one
println(list1.last) // 7
// 4. the initial data (without the last one)
println(list1.init) // List(1, 2, 3, 4, 5, 6)
// 5. reverse
println(list1.reverse) // List(7, 6, 5, 4, 3, 2, 1)
// 6. get the elements
println(list1.take(3)) // List(1, 2, 3)
println(list1.takeRight(3)) // List(5, 6, 7)
// 7. delete eletements
println(list1.drop(3)) // List(4, 5, 6, 7)
println(list1.dropRight(3)) // List(1, 2, 3, 4)
// 8. union
println(list1.union(list2)) // List(1, 2, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 9, 10)
// 9. intersect
println(list1.intersect(list2)) // List(4, 5, 6, 7)
// 10. diff
println(list1.diff(list2)) // List(1, 2, 3)
// 11. zip
println(list1.zip(list2)) // List((1,4), (2,5), (3,6), (4,7), (5,8), (6,9), (7,10))
// 12. slide
list1.sliding(2, 5).foreach(println)
// List(1, 2)
// List(6, 7)
}
}
7.3. 集合计算简单函数
- sorted:对一个集合进行自然排序,通过传递隐式的 Ordering
- sortBy:对一个属性或多个属性进行排序,通过它的类型。
- sortWith:基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑
package com.michael.learn.day05
object TestList05 {
def main(args: Array[String]): Unit = {
val list: List[Int] = List(1, 5, -3, 4, 2, -7, 6)
// 1. sum
println(list.sum) // 9
// 2. product by
println(list.product) // 5040
// 3. max
println(list.max) // 6
// 4. min
println(list.min) // -7
// 5. sort
// 5.1. sort by element size
println(list.sortBy(x => x)) // List(-7, -3, 1, 2, 4, 5, 6)
// 5.2. sort by absolutely size
println(list.sortBy(x => x.abs)) // List(1, 2, -3, 4, 5, 6, -7)
// 5.3. sort by ascending element size
println(list.sortWith((x, y) => x < y)) // List(-7, -3, 1, 2, 4, 5, 6)
// 5.4. sort by descending element size
println(list.sortWith((x, y) => x > y)) // List(6, 5, 4, 2, 1, -3, -7)
}
}
7.4. 集合计算高级函数
- 过滤:遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
- 转化/映射(map):将集合中的每一个元素映射到某一个函数
- 扁平化
- 扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten 操作集合中的每个元素的子元素映射到某个函数并返回新集合
- 分组(group):按照指定的规则对集合的元素进行分组
- 简化(归约)
- 折叠
7.4.1. Basic functions
package com.michael.learn.day05
object TestList6 {
def main(args: Array[String]): Unit = {
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
val nestedList: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9, 10))
val wordList: List[String] = List("hello world", "hello michael", "hello scala")
// 1. filter
println(list.filter(x => x % 2 == 0)) // List(2, 4, 6, 8)
// 2. map
println(list.map(_+1)) // List(2, 3, 4, 5, 6, 7, 8, 9, 10)
// 3. flatten
println(nestedList.flatten) // List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 4. flatten+map(map first then flatten)
println(wordList.flatMap(x => x.split(" "))) // List(hello, world, hello, michael, hello, scala)
// 5. group
println(list.groupBy(_ % 2)) // Map(1 -> List(1, 3, 5, 7, 9), 0 -> List(2, 4, 6, 8))
}
}
7.4.1. Reduce
Reduce 简化(归约) :通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最终获取结果
package com.michael.learn.day05
object TestList07 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
// 将数据两两结合,实现运算规则
val i:Int = list.reduce(_-_)
println("i = " + i) // i = -8 (1-2-3-4=-8)
// 从源码的角度,reduce 底层调用的其实就是 reduceLeft
println("i2 = " + list.reduceLeft(_-_)) // i2 = -8
println("i3 = " + list.reduceRight(_-_)) // i2 = -2 (4-3-2-1=-2)
}
}
7.4.2. Fold
Fold 折叠:化简的一种特殊情况
package com.michael.learn.day05
object TestList08 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
// fold 方法使用了函数柯里化,存在两个参数列表
// 第一个参数列表为 : 零值(初始值)
// 第二个参数列表为: 简化规则
// fold 底层其实为 foldLeft
println(list.fold(1)(_-_)) // -9 (1-1-2-3-4) = -9)
println(list.foldLeft(5)(_-_)) // -5
println(list.foldRight(10)(_-_)) // 8 (1-(2-((3-(4-10))))=8)
}
}
7.4.3. 两两合并
package com.michael.learn.day05
import scala.collection.mutable
object TestMap02 {
def main(args: Array[String]): Unit = {
// 两个 Map 的数据合并
val map1 = mutable.Map("a"->1, "b"->2, "c"->3)
val map2 = mutable.Map("a"->4, "b"->5, "d"->6)
val map3:mutable.Map[String, Int] = map2.foldLeft(map1){
(map, kv) => {
val k = kv._1
val v = kv._2
map(k) = map.getOrElse(k, 0) +v
map
}
}
println(map3) // Map(b -> 7, d -> 6, a -> 5, c -> 3)
}
}
7.4.4. Word Count实战一
单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果
package com.michael.learn.day05
object TestWordCount {
def main(args: Array[String]): Unit = {
val stringList = List("Hello Scala Hbase kafka", "Hello Scala Hbase", "Hello Scala", "Hello")
// 1. convert each string into words
val wordList:List[String] = stringList.flatMap(_.split(" "))
println(wordList) // List(Hello, Scala, Hbase, kafka, Hello, Scala, Hbase, Hello, Scala, Hello)
// 2. group by
val wordToWordsMap:Map[String, List[String]] = wordList.groupBy(word => word)
println(wordToWordsMap) // Map(Hello -> List(Hello, Hello, Hello, Hello), Hbase -> List(Hbase, Hbase), kafka -> List(kafka), Scala -> List(Scala, Scala, Scala))
// 3. count
val wordToCountMap:Map[String, Int] = wordToWordsMap.map(tuple =>(tuple._1, tuple._2.size))
println(wordToCountMap) // Map(Hello -> 4, Hbase -> 2, kafka -> 1, Scala -> 3)
// 4. sort
val sortList:List[(String, Int)] = wordToCountMap.toList.sortWith{_._2 > _._2}
println(sortList) // List((Hello,4), (Scala,3), (Hbase,2), (kafka,1))
// 5. top 3
println(sortList.take(3)) // List((Hello,4), (Scala,3), (Hbase,2))
}
}
8. 队列
Scala 也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和 dequeue。
package com.michael.learn.day05
import scala.collection.mutable
object TestQueue {
def main(args: Array[String]): Unit = {
val que = new mutable.Queue[String]()
que.enqueue("a", "b", "c")
println(que.dequeue()) // a
println(que.dequeue()) // b
println(que.dequeue()) // c
}
}
9. 并行集合
Scala 为了充分使用多核 CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算
package com.michael.learn.day05
object TestPar {
def main(args: Array[String]): Unit = {
val result1 = (0 to 5).map{case _ => Thread.currentThread.getName}
val result2 = (0 to 5).par.map{case _ => Thread.currentThread.getName}
println(result1) // Vector(main, main, main, main, main, main)
println(result2) // ParVector(scala-execution-context-global-11, scala-execution-context-global-11, scala-execution-context-global-11, scala-execution-context-global-12, scala-execution-context-global-14, scala-execution-context-global-12)
}
}