Skip to content

第 7 章 集 合 ​

· 7.1 集合简介 ​

1) Scala 的集合有三大类:序列 Seq、集Set、映射 Map,所有的集合都扩展自 Iterable

特质。

2) 对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包

不可变集合:scala.collection.immutable 可变集合: scala.collection.mutable

3) Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象, 而不会对原对象进行修改。类似于 java 中的 String 对象

4) 可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象

建议:在操作集合的时候,不可变用符号,可变用方法 ​

7.1.1

不可变集合继承图

1)Set 、 Map 是 Java 中 也 有 的 集 合2)Seq 是 Java 没有的,我们发现 List 归属到Seq 了,因此这里的 List 就和 Java 不是同一个概念了

3) 我们前面的for 循环有一个 1 to 3,就是 IndexedSeq 下的 Range

4) String 也是属于 IndexedSeq

5) 我们发现经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列)

6) 大家注意Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序

7) IndexedSeq 和LinearSeq 的区别:

(1) IndexedSeq 是通过索引来查找和定位,因此速度快,比如String 就是一个索引集

合,通过索引即可定位

(2) LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找

7.1.2 可变集合继承图 ​

7.2 数组 ​

7.2.1 不可变数组 ​

1) 第一种方式定义数组

定义:val arr1 = new Array[Int](10)

(1)new 是关键字

(2)[Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定Any

(3)(10),表示数组的大小,确定后就不可以变化

2) 案例实操

 

object TestArray{ def main(args: Array[String]): Unit = { //(1)数组定义val arr01 = new Array[Int](4)



println(arr01.length) // 4 //(2)数组赋值//(2.1)修改某个元素的值arr01(3) = 10//(2.2)采用方法的形式给数组赋值arr01.update(0,1) //(3)遍历数组//(3.1)查看数组println(arr01.mkString(",")) //(3.2) 普 通 遍 历 for (i <- arr01) {println(i)} //(3.3)简化遍历def printx(elem:Int): Unit = { println(elem)}arr01.foreach(printx)// arr01.foreach((x)=>{println(x)})// arr01.foreach(println(_)) arr01.foreach(println) //(4)增加元素(由于创建的是不可变数组,增加元素,其实是产生新的数组)println(arr01)val ints: Array[Int] = arr01 :+ 5 println(ints)}}

3) 第二种方式定义数组val arr1 = Array(1, 2)

(1) 在定义数组时,直接赋初始值

(2) 使用apply 方法创建数组对象

4) 案例实操


object TestArray{ def main(args: Array[String]): Unit = { var arr02 = Array(1, 3, "bobo") println(arr02.length)for (i <- arr02) {



println(i)}}}

7.2.2 可变数组 ​

1)定义变长数组

val arr01 = ArrayBuffer[Any](3, 2, 5)

(1)[Any]存放任意数据类型

(2)(3, 2, 5)初始化好的三个元素

(3) ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer 2)案例实操

(1) ArrayBuffer 是有序的集合

(2) 增加元素使用的是 append 方法(),支持可变参数

import scala.collection.mutable.ArrayBuffer object TestArrayBuffer {def main(args: Array[String]): Unit = { //(1)创建并初始赋值可变数组val arr01 = ArrayBuffer[Any](1, 2, 3) //(2)遍历数组for (i <- arr01) { println(i)}println(arr01.length) // 3 println("arr01.hash=" + arr01.hashCode()) //(3)增加元素//(3.1)追加数据arr01.+=(4)//(3.2)向数组最后追加数据arr01.append(5,6)//(3.3)向指定的位置插入数据arr01.insert(0,7,8) println("arr01.hash=" + arr01.hashCode()) //(4)修改元素

7.2.3 不可变数组与可变数组的转换 ​

1) 说明

arr1.toBuffer //不可变数组转可变数组arr2.toArray //可变数组转不可变数组

(1) arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化

(2) arr1.toBuffer 返回结果才是一个可变数组,arr1 本身没有变化

2) 案例实操

object TestArrayBuffer { def main(args: Array[String]): Unit = { //(1)创建一个空的可变数组val arr2 = ArrayBuffer[Int]() //(2)追加值arr2.append(1, 2, 3)println(arr2) // 1,2,3 //(3)ArrayBuffer ==> Array//(3.1)arr2.toArray 返回的结果是一个新的定长数组集合//(3.2)arr2 它没有变化val newArr = arr2.toArray println(newArr) //(4)Array ===> ArrayBuffer//(4.1)newArr.toBuffer 返回一个变长数组 newArr2//(4.2)newArr 没有任何变化,依然是定长数组val newArr2 = newArr.toBuffer newArr2.append(123) println(newArr2)}



}

7.2.4 多维数组 ​

1) 多维数组定义

val arr = Array.ofDim[Double](3,4)

说明:二维数组中有三个一维数组,每个一维数组中有四个元素

2) 案例实操

object DimArray { def main(args: Array[String]): Unit = { //(1)创建了一个二维数组, 有三个元素,每个元素是,含有 4 个元素一维数组()val arr = Array.ofDim[Int](3, 4) arr(1)(2) = 88 //(2)遍历二维数组for (i <- arr) { //i 就是一维数组for (j <- i) {print(j + " ")} println()}}}

7.3 列表List ​

7.3.1 不可变 List

1) 说明

(1) List 默认为不可变集合

(2) 创建一个 List(数据有顺序,可重复)

(3) 遍历 List

(4) List 增加数据

(5) 集合间合并:将一个整体拆成一个一个的个体,称为扁平化

(7)空集合 Nil

2) 案例实操

object TestList { def main(args: Array[String]): Unit = { //(1)List 默认为不可变集合//(2)创建一个 List(数据有顺序,可重复) val list: List[Int] = List(1,2,3,4,3) //(7)空集合 Nilval list5 = 1::2::3::4::Nil //(4)List 增加数据//(4.1)::的运算规则从右向左//val list1 = 5::list val list1 = 7::6::5::list//(4.2)添加到第一个元素位置val list2 = list.+:(5) //(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化val list3 = List(8,9)//val list4 = list3::list1 val list4 = list3:::list1 //(6)取指定数据println(list(0)) //(3)遍历 List//list.foreach(println)//list1.foreach(println)//list3.foreach(println)//list4.foreach(println) list5.foreach(println)}}

7.3.2 可变ListBuffer ​

1) 说明

(1) 创建一个可变集合 ListBuffer

(2) 向集合中添加数据

2) 案例实操


import scala.collection.mutable.ListBuffer object TestList {def main(args: Array[String]): Unit = { //(1)创建一个可变集合val buffer = ListBuffer(1,2,3,4) //(2)向集合中添加数据buffer.+=(5) buffer.append(6) buffer.insert(1,2) //(3)打印集合数据buffer.foreach(println) //(4)修改数据buffer(1) = 6 buffer.update(1,7) //(5)删除数据buffer.-(5)buffer.-=(5) buffer.remove(5)}}

7.4 Set 集合 ​

默认情况下, Scala 使用的是不可变集合, 如果你想使用可变集合, 需要引用

scala.collection.mutable.Set 包

7.4.1 不可变 Set ​

1) 说明

(1) Set 默认是不可变集合,数据无序

(2) 数据不可重复

(3) 遍历集合

2) 案例实操

 def main(args: Array[String]): Unit = { //(1)Set 默认是不可变集合,数据无序val set = Set(1,2,3,4,5,6) //(2)数据不可重复val set1 = Set(1,2,3,4,5,6,3) //(3)遍历集合for(x<-set1){ println(x)}}}

7.4.2 可变mutable.Set ​

1) 说明

(1) 创建可变集合 mutable.Set

(2) 打印集合

(3) 集合添加元素

(4) 向集合中添加元素,返回一个新的 Set

(5) 删除数据

2) 案例实操

object TestSet { def main(args: Array[String]): Unit = { //(1)创建可变集合val set = mutable.Set(1,2,3,4,5,6) //(3)集合添加元素set += 8 //(4)向集合中添加元素,返回一个新的 Set val ints = set.+(9)println(ints) println("set2=" + set) //(5)删除数据set-=(5)


 //(2)打印集合set.foreach(println) println(set.mkString(","))}}

7.5 Map 集合 ​

Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value) 映射

7.5.1 不可变 Map ​

1) 说明

(1) 创建不可变集合 Map

(2) 循环打印

(3) 访问数据

(4) 如果 key 不存在,返回 0

2) 案例实操

 

object TestMap { def main(args: Array[String]): Unit = {// Map//(1)创建不可变集合 Mapval map = Map( "a"->1, "b"->2, "c"->3 ) //(3)访问数据for (elem <- map.keys) {// 使用 get 访问 map 集合的数据,会返回特殊类型 Option(选项):有值(Some),无值(None)println(elem + "=" + map.get(elem).get)} //(4) 如 果 key 不 存 在 , 返 回 0 println(map.get("d").getOrElse(0)) println(map.getOrElse("d", 0)) //(2)循环打印map.foreach((kv)=>{println(kv)})}}

7.5.2 可变Map ​

1) 说明

(1) 创建可变集合

(2) 打印集合

(3) 向集合增加数据

(4) 删除数据

(5) 修改数据

2) 案例实操


object TestSet { def main(args: Array[String]): Unit = { //(1)创建可变集合val map = mutable.Map( "a"->1, "b"->2, "c"->3 ) //(3)向集合增加数据map.+=("d"->4) // 将数值 4 添加到集合,并把集合中原值 1 返回val maybeInt: Option[Int] = map.put("a", 4) println(maybeInt.getOrElse(0)) //(4)删除数据map.-=("b", "c") //(5)修改数据map.update("d",5) map("d") = 5 //(2)打印集合map.foreach((kv)=>{println(kv)})}}

7.6 元组 ​

1) 说明

元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就

是将多个无关的数据封装为一个整体,称为元组。注意:元组中最大只能有 22 个元素。

2) 案例实操

(1) 声明元组的方式:(元素 1,元素 2,元素 3)

(2) 访问元组

(3) Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为对偶

object TestTuple { def main(args: Array[String]): Unit = { //(1)声明元组的方式:(元素 1,元素 2,元素 3)val tuple: (Int, String, Boolean) = (40,"bobo",true) //(2)访问元组//(2.1)通过元素的顺序进行访问,调用方式:_顺序号println(tuple._1)println(tuple._2) println(tuple._3) //(2.2)通过索引访问数据println(tuple.productElement(0)) //(2.3)通过迭代器访问数据for (elem <- tuple.productIterator) { println(elem)} //(3)Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为对偶val map = Map("a"->1, "b"->2, "c"->3) val map1 = Map(("a",1), ("b",2), ("c",3)) map.foreach(tuple=>{println(tuple._1 + "=" + tuple._2)})}}

7.7 集合常用函数 ​

7.7.1 基本属性和常用操作

1) 说明

(1) 获取集合长度

(2) 获取集合大小

(3) 循环遍历

(4) 迭代器

(5) 生成字符串

(6) 是否包含

2) 案例实操

object TestList { def main(args: Array[String]): Unit = { val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7) //(1)获取集合长度println(list.length) //(2)获取集合大小,等同于 length println(list.size) //(3)循环遍历list.foreach(println) //(4)迭代器for (elem <- list.itera tor) { println(elem)} //(5)生成字符串println(list.mkString(",")) //(6)是否包含println(list.contains(3))}}

7.7.2 衍生集合 ​

1) 说明

(1) 获取集合的头

(2) 获取集合的尾(不是头的就是尾)

(3) 集合最后一个数据

(4) 集合初始数据(不包含最后一个)

(5) 反转

(6) 取前(后)n 个元素

(7) 去掉前(后)n 个元素

(8) 并集

(9) 交集

(10) 差集

(11) 拉链

(12) 滑窗

2) 案例实操

object TestList { 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)获取集合的头println(list1.head) //(2)获取集合的尾(不是头的就是尾) println(list1.tail) //(3)集合最后一个数据println(list1.last) //(4)集合初始数据(不包含最后一个) println(list1.init) //(5)反转println(list1.reverse) //(6)取前(后)n 个元素
println(list1.take(3)) println(list1.takeRight(3)) //(7)去掉前(后)n 个元素println(list1.drop(3)) println(list1.dropRight(3)) //(8)并集println(list1.union(list2)) //(9)交集println(list1.intersect(list2)) //(10)差集println(list1.diff(list2)) //(11)拉链 注:如果两个集合的元素个数不相等,那么会将同等数量的数据进行拉链,多余的数据省略不用println(list1.zip(list2)) //(12)滑窗list1.sliding(2, 5).foreach(println)}}

7.7.3 集合计算简单函数 ​

1) 说明

(1) 求和

(2) 求乘积

(3) 最大值

(4) 最小值

(5) 排序

2)

实操

(1)sorted

对一个集合进行自然排序,通过传递隐式的Ordering

(2) sortBy

对一个属性或多个属性进行排序,通过它的类型。

(3) sortWith

基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑。

7.7.4 集合计算高级函数 ​

1) 说明

(1) 过滤

遍历一个集合并从中获取满足指定条件的元素组成一个新的集合

(2) 转化/映射(map) ​

将集合中的每一个元素映射到某一个函数

(3) 扁平化

(4) 扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten 操作集合中的每个元素的子元素映射到某个函数并返回新集合

(5) 分组(group) ​

按照指定的规则对集合的元素进行分组

(6) 简化(归约)

(7) 折叠

2) 实操

3) Reduce 方法 ​

Reduce 简化(归约) :通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最终获取结果。

案例实操

object TestReduce { def main(args: Array[String]): Unit = { val list = List(1,2,3,4)// 将数据两两结合,实现运算规则val i: Int = list.reduce( (x,y) => x-y ) println("i = " + i) // 从源码的角度,reduce 底层调用的其实就是 reduceLeft//val i1 = list.reduceLeft((x,y) => x-y) // ((4-3)-2-1) = -2val i2 = list.reduceRight((x,y) => x-y) println(i2)}}

4) Fold 方法 ​

Fold 折叠:化简的一种特殊情况。

(1) 案例实操:fold 基本使用


object TestFold { def main(args: Array[String]): Unit = { val list = List(1,2,3,4)// fold 方法使用了函数柯里化,存在两个参数列表// 第一个参数列表为 : 零值(初始值)// 第二个参数列表为: 简化规则// fold 底层其实为 foldLeftval i = list.foldLeft(1)((x,y)=>x-y) val i1 = list.foldRight(10)((x,y)=>x-y)println(i) println(i1)}}

(2) 案例实操:两个集合合并

 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._2map(k) = map.getOrElse(k, 0) + v map}} println(map3)}}

7.7.5 普通WordCount 案例 ​

1) 需求

单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果

2) 需求分析

3) 案例实操

object TestWordCount { def main(args: Array[String]): Unit = {

7.7.6 复杂WordCount 案例

1) 方式一

object TestWordCount { def main(args: Array[String]): Unit = { // 第一种方式(不通用)val tupleList = List(("Hello Scala Spark World ", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1)) val stringList: List[String] = tupleList.map(t=>(t._1 + " ") * t._2) //val words: List[String] = stringList.flatMap(s=>s.split(" "))val words: List[String] = stringList.flatMap(_.split(" "))

2) 方式二

object TestWordCount { def main(args: Array[String]): Unit = { val tuples = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1)) // (Hello,4),(Scala,4),(Spark,4),(World,4)// (Hello,3),(Scala,3),(Spark,3)// (Hello,2),(Scala,2)// (Hello,1)val wordToCountList: List[(String, Int)] = tuples.flatMap{t => {val strings: Array[String] = t._1.split(" ") strings.map(word => (word, t._2))}} // Hello, List((Hello,4), (Hello,3), (Hello,2), (Hello,1))// Scala, List((Scala,4), (Scala,3), (Scala,2)// Spark, List((Spark,4), (Spark,3)// Word, List((Word,4))val wordToTupleMap: Map[String, List[(String, Int)]] = wordToCountList.groupBy(t=>t._1) val stringToInts: Map[String, List[Int]] = wordToTupleMap.mapValues {datas => datas.map(t => t._2)}stringToInts

7.8 队列

1) 说明

Scala 也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和dequeue。

2) 案例实操

object TestQueue { def main(args: Array[String]): Unit = { val que = new mutable.Queue[String]() que.enqueue("a", "b", "c")println(que.dequeue()) println(que.dequeue()) println(que.dequeue())}}

7.9 并行集合 ​

1) 说明

Scala 为了充分使用多核 CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。

2) 案例实操

object TestPar { def main(args: Array[String]): Unit = {



 val result1 = (0 to 100).map{case _ => Thread.currentThread.getName}val result2 = (0 to 100).par.map{case _ => Thread.currentThread.getName} println(result1) println(result2)}}

Released under the MIT License.