Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable特质。
对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包中
不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable
Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 java 中的 String 对象
可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象
建议:在操作集合的时候,不可变用符号,可变用方法
其中蓝色是具体的class,绿色是trait。
1)Set、Map 是 Java 中也有的集合
2)Seq 是 Java 没有的,我们发现 List 归属到 Seq 了,因此这里的 List 就和 Java 不是同一个概念了
3)我们前面的 for 循环有一个 1 to 3,就是 IndexedSeq 下的 Range
4)String 也是属于 IndexedSeq,String和Array是通过隐式转换成了IndexedSeq
5)我们发现经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列)
6)注意 Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序
7)IndexedSeq 和 LinearSeq 的区别:
a、IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集合,通过索引即可定位
b、LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
可变集合类型
第一种方式定义数组
val arr1 = new Array[Int](10)
(1)new 是关键字
(2)[Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定 Any
(3)(10)表示数组的大小,确定后就不可以变化
第二种方式定义数组
val arr1 = Array(1, 2)
(1)在定义数组时,直接赋初始值
(2)使用 apply 方法创建数组对象
object TestImmutableArray {
def main(args: Array[String]): Unit = {
// 1、创建数组
val arr = new Array[Int](5)
// 2、另一种创建的方式
val arr2 = Array(14, 56, 78)
// 3、访问数组的元素
println(arr(0)) // 0
println(arr(4)) // 0
// println(arr(5)) error
arr(0) = 1
arr(4) = 109
println(arr(0)) // 1
println(arr(4)) // 109
// 4、数组遍历
// 4.1、普通for循环
// 相当与for (i <- 0 until arr.length)
for (i <- arr.indices) {
println(arr(i))
}
// 4.2、直接遍历所有元素,增强for循环
for (elem <- arr2) {
println(elem)
}
// 4.3、迭代器的使用
val iter = arr2.iterator
while (iter.hasNext) {
println(iter.next())
}
// 4.4、调用foreach方法
arr2.foreach((elem: Int) => {
println(elem)
})
// 简写
arr.foreach(println)
println(arr2.mkString("--")) // 14--56--78
// 5、添加元素
val newArr = arr2.:+(35) // :+()从数组后面追加一个元素,并返回新的数组
println(arr2.mkString("--")) // 14--56--78
println(newArr.mkString("--")) // 14--56--78--35
val newArr2 = newArr.+:(98) // +:()从数组前面追加一个元素,并返回新的数组
println(newArr2.mkString("--")) // 98--14--56--78--35
val newArr3 = newArr2 :+ 15
val newArr4 = 19 +: 15 +: newArr3 :+ 67 // 如果是以:结尾的话,需要更换位置
println(newArr4.mkString(",")) // 19,15,98,14,56,78,35,15,67
}
}
定义变长数组
val arr01 = ArrayBuffer[Any](3, 2, 5)
(1)[Any]存放任意数据类型
(2)(3, 2, 5)初始化好的三个元素
(3)ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer
(4)ArrayBuffer 是有序的集合
(5)增加元素使用的是 append 方法(),支持可变参数
可变数组和不可变数组的转换:
arr1.toBuffer //不可变数组转可变数组,返回结果才是一个可变数组,arr1 本身没有变化
arr2.toArray //可变数组转不可变数组,返回结果才是一个不可变数组,arr2 本身没有变化
object TestArrayBuffer {
def main(args: Array[String]): Unit = {
// 1、创建一个可变数组
val arr1 = new ArrayBuffer[Int]()
val arr2 = ArrayBuffer(1, 3, 46, 7)
println(arr1.mkString(",")) // 无数据
println(arr2) // ArrayBuffer(1, 3, 46, 7)
println(arr2.toString()) // ArrayBuffer(1, 3, 46, 7)
// 2、访问数组中的元素
// println(arr1(0)) // error
println(arr2(1))
arr2(2) = 17
println(arr2(1))
// 3、添加元素
val newArr1 = arr1 :+ 15 // :+是针对不可变数组的添加元素的
println(newArr1) // ArrayBuffer(15)
println(arr1) // ArrayBuffer()
val newArr2 = arr1 += 19 // 这里是把arr1的地址给newArr2了,因此不推荐把可变数组处理的结果赋值给别的
println(arr1) // ArrayBuffer(19)
println(newArr2) // ArrayBuffer(19)
println(newArr2 == arr1) // true
77 +=: arr1
println(arr1) // ArrayBuffer(77, 19)
arr1.append(36)
arr1.prepend(45, 88)
arr1.insert(1, 99999, 1000)
println(arr1) // ArrayBuffer(45, 99999, 1000, 88, 77, 19, 36)
arr1.insertAll(2, newArr1)
arr1.appendAll(newArr1)
arr1.prependAll(newArr1)
println(arr1) // ArrayBuffer(15, 45, 99999, 15, 1000, 88, 77, 19, 36, 15)
// 对于不可变数组推荐使用 :+ 和 +: 来进行处理
// 对于可变数组推荐使用方法来处理
// 4、删除元素
arr1.remove(1)
println(arr1) // ArrayBuffer(15, 99999, 15, 1000, 88, 77, 19, 36, 15)
arr1.remove(1, 2)
println(arr1) // ArrayBuffer(15, 1000, 88, 77, 19, 36, 15)
arr1 -= 77
println(arr1) // ArrayBuffer(15, 1000, 88, 19, 36, 15)
arr1 -= 888
println(arr1) // ArrayBuffer(15, 1000, 88, 19, 36, 15)
// 5、可变数组转换成不可变数组
val arr: ArrayBuffer[Int] = ArrayBuffer(23, 45, 67)
val newArr: Array[Int] = arr.toArray
println(newArr.mkString(",")) // 23,45,67
println(arr) // ArrayBuffer(23, 45, 67)
// 6、不可变数组转换为可变数组
val buffer: mutable.Buffer[Int] = newArr.toBuffer
println(buffer) // ArrayBuffer(23, 45, 67)
println(newArr) // [I@6b2fad11
println(newArr.mkString(",")) // 23,45,67
}
}
在大数据的处理过程中,如果用到了数组的话,推荐使用不可变数组进行操作,并且能用不可变就用不可变。
多维数组定义
val arr = Array.ofDim[Double](3,4)
说明:二维数组中有三个一维数组,每个一维数组中有四个元素
object TestMulArray {
def main(args: Array[String]): Unit = {
// 1、创建一个二位数组
val array: Array[Array[Int]] = Array.ofDim[Int](2, 3)
// 2、访问元素
array(0)(2) = 9
array(1)(0) = 25
for (i <- 0 until array.length; j <- 0 until array(i).length) {
println(array(i)(j))
}
for (i <- array.indices; j <- array(i).indices) {
print(array(i)(j) + "\t")
if (j == array(i).length - 1) println()
}
array.foreach(line => line.foreach(println))
// 简写
array.foreach(_.foreach(println))
}
}
object TestList {
def main(args: Array[String]): Unit = {
// (1)List 默认为不可变集合
// (2)创建一个 List(数据有顺序,可重复)
val list1 = List(23, 56, 89)
println(list1) // List(23, 56, 89)
println(list1(1))
// list1(1) = 12 // error
// (3)遍历 List
list1.foreach(println)
// (4)List 增加数据
val list2 = list1 :+ 10
val list3 = 10 +: list1
println(list1) // List(23, 56, 89)
println(list2) // List(23, 56, 89, 10)
println(list3) // List(10, 23, 56, 89)
val list4 = list2.::(51)
println(list2) // List(23, 56, 89, 10)
println(list4) // List(51, 23, 56, 89, 10)
// 空集合 Nil
val list5 = Nil.::(13)
println(list5) // List(13)
val list6 = 42 :: 56 :: 44 :: Nil
println(list6) // List(42, 56, 44)
// (5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化
val list7 = list5 :: list6
println(list7) // List(List(13), 42, 56, 44)
val list9 = list5 ::: list6
println(list9) // List(13, 42, 56, 44)
val list10 = list5 ++ list6
println(list10) // List(13, 42, 56, 44)
}
}
object TestListBuffer {
def main(args: Array[String]): Unit = {
// 1、创建可变列表
val list1 = new ListBuffer[Int]()
val list2 = ListBuffer(12, 34, 56)
println(list1) // ListBuffer()
println(list2) // ListBuffer(12, 34, 56)
// 2、添加元素
list1.append(12, 45)
list2.prepend(45, 67)
list1.insert(1, 19, 44)
println(list1) // ListBuffer(12, 19, 44, 45)
println(list2) // ListBuffer(45, 67, 12, 34, 56)
31 +=: 24 +=: list1 += 35 += 44 += 11
println(list1) // ListBuffer(31, 24, 12, 19, 44, 45, 35, 44, 11)
// 3、合并list
val list3 = list1 ++ list2
println(list1) // ListBuffer(31, 24, 12, 19, 44, 45, 35, 44, 11)
println(list2) // ListBuffer(45, 67, 12, 34, 56)
println(list3) // ListBuffer(31, 24, 12, 19, 44, 45, 35, 44, 11, 45, 67, 12, 34, 56)
list1 ++= list2
println(list1) // ListBuffer(31, 24, 12, 19, 44, 45, 35, 44, 11, 45, 67, 12, 34, 56)
println(list2) // ListBuffer(45, 67, 12, 34, 56)
val list4 = ListBuffer(1, 2, 3)
list4 ++=: list2
println(list4) // ListBuffer(1, 2, 3)
println(list2) // ListBuffer(1, 2, 3, 45, 67, 12, 34, 56)
// 4、修改元素
list2(3) = 444
list2.update(0, 111)
println(list2) // ListBuffer(111, 2, 3, 444, 67, 12, 34, 56)
// 5、删除元素
list2.remove(0)
list2 -= 67
println(list2) // ListBuffer(2, 3, 444, 12, 34, 56)
}
}
默 认 情 况 下 , Scala 使 用 的 是 不 可 变 集 合 , 如 果 你 想 使 用 可 变 集 合 , 需 要 引 用scala.collection.mutable.Set 包
Set 默认是不可变集合,数据无序,数据不可重复,因此可以使用Set来进行数据的去重。
object TestImmutableSet {
def main(args: Array[String]): Unit = {
// 1、创建一个Set
val set1 = Set(13, 45, 13, 45, 67, 8)
println(set1) // Set(13, 45, 67, 8)
// 2、添加元素
val set2 = set1 + 44
println(set1) // Set(13, 45, 67, 8)
println(set2) // Set(13, 45, 44, 67, 8)
// 3、合并Set
val set3 = Set(13, 45, 13, 99, 77)
val set4 = set2 ++ set3
println(set2) // Set(13, 45, 44, 67, 8)
println(set3) // Set(13, 45, 99, 77)
println(set4) // Set(77, 13, 45, 44, 67, 99, 8)
// 4、删除元素
val set5 = set3 - 13
println(set3) // Set(13, 45, 99, 77)
println(set5) // Set(45, 99, 77)
}
}
object TestMutableSet {
def main(args: Array[String]): Unit = {
// 1、创建一个Set
val set1 = mutable.Set(13, 45, 13, 45, 67, 8)
println(set1) // Set(13, 45, 67, 8)
// 2、添加元素
val set2 = set1 + 11
println(set1) // Set(13, 45, 67, 8)
println(set2) // Set(13, 45, 67, 11, 8)
set1 += 12
println(set1) // Set(13, 12, 45, 67, 8)
val flag1 = set1.add(123)
println(flag1) // true
println(set1) // Set(13, 12, 123, 45, 67, 8)
val flag2 = set1.add(123)
println(flag2) // false
println(set1) // Set(13, 12, 123, 45, 67, 8)
// 3、删除元素
set1 -= 12
val flag3 = set1.remove(13)
println(set1) // Set(45, 67, 123, 8)
val flag4 = set1.remove(13)
println(set1) // Set(45, 67, 123, 8)
// 4、合并两个Set
val set3 = mutable.Set(13, 45, 13, 44, 77)
val set4 = set1 ++ set3
println(set1) // Set(45, 67, 123, 8)
println(set3) // Set(45, 13, 44, 77)
println(set4) // Set(45, 67, 13, 123, 8, 44, 77)
set1 ++= set3
println(set1) // Set(45, 67, 13, 123, 8, 44, 77)
println(set3) // Set(45, 13, 44, 77)
}
}
Scala 中的 Map 和 Java 类似, 也是一个散列表,它存储的内容也是键值对(key-value)映射
object TestImmutableMap {
def main(args: Array[String]): Unit = {
// 1、创建map
val map1: Map[String, Int] = Map("a" -> 13, "b" -> 56, "hello" -> 8)
println(map1) // Map(a -> 13, b -> 56, hello -> 8)
println(map1.getClass) // class scala.collection.immutable.Map$Map3 3是3个元素
// 2、遍历元素
map1.foreach(println)
// (a,13)
// (b,56)
// (hello,8)
map1.foreach((kv: (String, Int)) => println(kv))
// 3、取map所有的key 或者value
for (key <- map1.keys) {
println(s"key is $key, value is ${map1.get(key)}")
// key is a, value is Some(13)
// key is b, value is Some(56)
// key is hello, value is Some(8)
}
// 4、访问某一个key的value
println("a: " + map1.get("a").get) // a: 13,这个写法不够安全
println("a: " + map1.getOrElse("a", "0")) // a: 13
// println("c: " + map1.get("c").get) // 这里会报错
println("c: " + map1.get("c")) // c: None
println("c: " + map1.getOrElse("c", 0)) // c: 0
println("a: " + map1("a")) // a: 13,这个等于map1.get("a").get
}
}
object TestMutableMap {
def main(args: Array[String]): Unit = {
// 1、创建map
val map1: mutable.Map[String, Int] = mutable.Map("a" -> 13, "b" -> 56, "hello" -> 8)
println(map1) // Map(a -> 13, b -> 56, hello -> 8)
println(map1.getClass) // class scala.collection.mutable.HashMap
// 2、添加元素
map1.put("c", 54)
map1.update("d", 3)
println(map1) // Map(b -> 56, d -> 3, a -> 13, c -> 54, hello -> 8)
map1 += (("e",13))
println(map1) // Map(e -> 13, b -> 56, d -> 3, a -> 13, c -> 54, hello -> 8)
// 3、删除元素
map1.remove("c")
println(map1.getOrElse("c", -1)) // -1
map1 -= "d"
println(map1) // Map(e -> 13, b -> 56, a -> 13, hello -> 8)
// 4、修改元素=插入元素
map1.put("c", 54)
map1.update("d", 3)
println(map1) // Map(e -> 13, b -> 56, d -> 3, a -> 13, c -> 54, hello -> 8)
// 5、合并两个Map
val map2: Map[String, Int] = Map("a" -> 33, "test" -> 19)
map1 ++= map2 // 添加并覆盖
println(map1) // Map(e -> 13, b -> 56, d -> 3, a -> 33, c -> 54, hello -> 8, test -> 19)
println(map2) // Map(a -> 33, test -> 19)
val map4: Map[String, Int] = Map("e" -> 999, "map" -> 77)
val map3: Map[String, Int] = map4 ++ map1
println(map3) // Map(e -> 13, test -> 19, map -> 77, a -> 33, b -> 56, c -> 54, hello -> 8, d -> 3)
}
}
元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组,即元素的组合。
注意:元组中最大只能有 22 个元素。
object TestTuple {
def main(args: Array[String]): Unit = {
// 1、创建元祖
val tuple: (String, Int, Char, Boolean) = ("hello", 100, 'a', true)
println(tuple) // (hello,100,a,true)
// 2、访问元组
println(tuple._1) // hello
println(tuple._2) // 100
println(tuple._3) // a
println(tuple._4) // true
println(tuple.productElement(1)) // 100
// 3、遍历元组数据
for (elem <- tuple.productIterator) {
println(elem)
}
// 4、嵌套元组
val mulTuple = (12, 0.3, "hello", (0, "scala"), 99)
println(mulTuple._4._2) // scala
}
}
Scala 也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和 dequeue。
object TestQueue {
def main(args: Array[String]): Unit = {
// 创建一个可变的队列
val queue = new mutable.Queue[String]()
queue.enqueue("a", "b", "hello") // Queue(a, b, hello)
println(queue) // a
println(queue.dequeue()) // Queue(b, hello)
println(queue) // b
println(queue.dequeue()) // Queue(hello)
println(queue)
// 不可变队列
val queue2 = Queue("a", "b", "hello")
val queue3 = queue2.enqueue("d")
println(queue2) // Queue(a, b, hello)
println(queue3) // Queue(a, b, hello, d)
}
}
Scala 为了充分使用多核 CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。
object TestParallel {
def main(args: Array[String]): Unit = {
val result = (1 to 100).map(
x => Thread.currentThread().getId
)
println(result) // 都是1
val result2 = (1 to 100).par.map(
x => Thread.currentThread().getId
)
println(result2) // 有很多不一样的线程id
// ParVector(10, 10, 10, 10, 10, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13)
}
}