♂️♂️ 写在前面
个人主页:csdn春和
推荐专栏:更多专栏尽在主页!
JavaWeb专栏(从入门到实战超详细!!!)
SSM专栏 (更新中…)
本期文章:Scala高级语法入门 (四) 一文彻底了解 Scala中的集合
如果对您有帮助还请三连支持,定会一 一回访!♂️
简介
Scala的集合有三大类:
序列Seq
、集Set
、映射Map
,所有的集合都扩展自Iterable特质。对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本
。
可变集合
可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素。而
不可变集合类
,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变,所以这里的不可变并不是变量本身的值不可变,而是变量指向的那个内存地址不可变
可变集合和不可变集合,在scala中该如何进行区分呢?我们一般可以根据集合所在包名进行区分:
1️⃣ scala.collection.immutable 不可变
2️⃣ scala.collection.mutablel> 可变
Scala 不可变集合
,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 java 中的 String 对象
可变集合
,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似 于 java 中 StringBuilder 对象
1、基本语法
val arr1 = new Array[Int](10) // 方式一
(1)new 是关键字
(2)[Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定 Any
(3)(10),表示数组的大小,确定后就不可以变化
val arr1 = Array(1, 2) // 方式二 使用的是伴生对象的apply方法
(1)在定义数组时,直接赋初始值
(2)使用 apply 方法创建数组对象
object Scala_Collection01_Array1 {
def main(args: Array[String]): Unit = {
// TODO 集合 数组 基本语法
// TODO 1、定义数组
val array = Array(1,2,3,4)
println(array.mkString(",")) // mkString方法将集合中的元素转为字符串输出 参数为指定一个分隔符
// TODO 2、修改数组中的值
array(0) = 9
array.update(3,7) // 采用update方法修改元素
println(array.mkString(","))
println("***************************************")
// TODO 3、遍历
// 普通遍历
for (i <- array) {
println(i)
}
}
}
scala中提供了另外一种简化遍历的方法 foreach
// 简化遍历
def arrayForeach(i:Int): Unit ={
println(i)
}
array.foreach(arrayForeach)
查看结果:
既然传递的参数是一个函数 那么我们就可以使用匿名函数 ,那么也可以使用匿名函数的至简原则来简化代码书写
// 简化写法
// array.foreach((i:Int) => {println(i)}) // 完整写法
// array.foreach((i:Int) => println(i)) // 省略{}
// array.foreach((i) => println(i)) // 参数类型可推导出来 类型可以省
// array.foreach(i => println(i)) // 参数只有一个 () 可以省略
array.foreach(println(_)) // 参数只出现一次 可以用_ 代替
2、基本操作
1、添加元素
// 2、添加元素
val ints1 = array1.+:(6)
val ints2 = array1.:+(6)
val array2 = Array(6, 7, 8, 9, 10)
// 将另一个数组添加到数组中
val ints3 = array1.++(array2)
val ints4 = array1 ++ array2
// 比较内存地址
println(array1 eq(ints1)) // false
println(array1 eq(ints2)) // false
scala默认提供的集合都是不可变得,操作数据的时候会产生新的集合
2、常用方法
object Scala_Collection01_Array3 {
def main(args: Array[String]): Unit = {
// TODO Array的常用方法
// 多维数组 ofDim
val array: Array[Array[Int]] = Array.ofDim[Int](3, 2)
array.foreach(list => println(list.mkString(",")))
// 合并数组 concat
val array1 = Array(1, 2, 3)
val array2 = Array(4, 5, 6)
val array3 = Array.concat(array1, array2)
println(array3.mkString(","))
// 创建指定范围的数组 range 前闭后开
val array4 = Array.range(0, 2)
println(array4.mkString(","))
// 创建并填充指定数的数组 fill 数组里面全是-1
val array5: Array[Int] = Array.fill[Int](5)(-1)
println(array5.mkString(","))
}
}
可变数组的定义方式和不可变数组一样 使用的是ArrayBuffer进行定义
object Scala_Collection02_ArrayBuffer1 {
def main(args: Array[String]): Unit = {
// TODO 可变数组
// 方式一:使用new关键字
val buffer = new ArrayBuffer[Int]
// 方式二:使用伴生对象声明
// val buffer = ArrayBuffer(1, 2, 3, 4)
// 增加数据
buffer.append(1, 2, 3, 4)
// 修改数据
buffer.update(0, 5) // 5 2 3 4
buffer(1) = 6
// 删除数据
val i: Int = buffer.remove(2) // 删除下标索引为2的元素 5 2 4
buffer.remove(1, 2) // 删除下标索引为1起 删除两个元素 5
// 查询数据
println(buffer(0)) // 5
// 循环集合
for (i <- buffer) {
println(i)
}
// 简化循环
buffer.foreach(println)
}
}
在可变数组中
使用 ++ 运算会产生新的数组
使用++= 不会产生新的数组
// 使用 ++ 运算符会产生新的集合数组
val buffer4: ArrayBuffer[Int] = buffer1 ++ buffer2
// 使用 ++= 运算符会更新之前的集合,不会产生新的数组
val buffer5: ArrayBuffer[Int] = buffer1 ++= buffer2
println( buffer1 eq buffer4 ) // false
println( buffer1 eq buffer5 ) // true
object Scala_Collection02_ArrayBuffer2 {
def main(args: Array[String]): Unit = {
// TODO 可变数组
val buffer = ArrayBuffer(1,2,3,4) // 可变数组
val array = Array(4,5,6,7) // 不可变数组
// 将不可变数组转换为可变数组
val buffer1: mutable.Buffer[Int] = array.toBuffer
// 将可变数组转换为不可变数组
val array1: Array[Int] = buffer.toArray
}
}
scala也提供了将java集合转为scala集合的API
// java集合 <=> Scala集合
import scala.collection.JavaConverters._
val list: util.ArrayList[Nothing] = new util.ArrayList()
list.asScala.foreach(println) // java集合转为scala集合
val java: util.List[Int] = List(1, 2, 3, 4).asJava // scala集合转为java集合
list存放数据有序 可以放重复数据的集合,有序指的是插入顺序有序
不可变list
// Seq集合
val list = List(1,2,3,4)
// 增加数据
val list1: List[Int] = list :+ 1
println(list1 eq list) // fasle
println(list1.mkString(","))
val list2: List[Int] = 1 +: list
println(list2.mkString(","))
println("*****************")
val list3: List[Int] = list.updated(1,5)
println(list eq list3) // false 不可变集合 会产生新的集合
// Seq集合
val list1 = List(1, 2, 3, 4)
// 空集合
val list2: List[Nothing] = List()
val nil = Nil // nil表示空集合
println(list2 eq nil) // true
// 创建集合
val list3: List[Int] = 1 :: 2 :: 3 :: Nil // 将 1 2 3 放入空集合中
val list4: List[Int] = list1 ::: Nil // 将list拆分装入空集合
// 连接集合
val list5: List[Int] = List.concat(list3, list4)
println(list5.mkString(","))
// 创建一个指定重复数量的元素列表 fill
val list6: List[String] = List.fill[String](3)("a")
list6.foreach(println)
可变list
object Scala_Collection05_Seq2 {
def main(args: Array[String]): Unit = {
// TODO Seq可变list集合
// 可变集合
val buffer = new ListBuffer[Int]()
// 增加数据
buffer.append(1, 2, 3, 4) // 1 2 3 4
// 修改数据
buffer.update(1, 3) // 改变自身 1 3 3 4
val buffer1 = buffer.updated(1, 3) // 修改之后产生新的集合
// 删除数据
buffer.remove(2) // 1 3 4
buffer.remove(2, 2) // 1 3
// 获取数据
println(buffer(1)) // 3
// 遍历集合
buffer.foreach(println) // 1 3
}
}
相互转换
object Scala_Collection05_Seq3 {
def main(args: Array[String]): Unit = {
// TODO 可变list和不可变list的相互转化
val buffer = ListBuffer(1, 2, 3, 4)
val list = List(5, 6, 7, 8)
// 可变集合转变为不可变集合
val list1: List[Int] = buffer.toList
// 不可变集合转变为可变集合
val buffer1: mutable.Buffer[Int] = list.toBuffer
}
}
数据无序且不可重复
数据无序:
val set = Set(1,2,3,4,5,6,7,8)
println(set)
不可重复:
val set = Set(1,2,3,4,1,2,3,4)
println(set)
不可变set
// 增加数据
val set3: Set[Int] = set1 + 5 + 6
val set4: Set[Int] = set1.+(6,7,8)
println( set1 eq set3 ) // false
println( set1 eq set4 ) // false
set4.foreach(println)
// 删除数据
val set5: Set[Int] = set1 - 2 - 3
set5.foreach(println)
val set6: Set[Int] = set1 ++ set2
set6.foreach(println)
println("********")
val set7: Set[Int] = set2 ++: set1
set7.foreach(println)
println(set6 eq set7)
可变set
object Scala_Collection06_Set1 {
def main(args: Array[String]): Unit = {
// TODO Set集合 可变set
val set1 = mutable.Set(1,2,3,4)
val set2 = mutable.Set(5,6,7,8)
// 增加数据 add方法
set1.add(5)
// 添加数据 set中的update是对数据进行处理
set1.update(6,true)
println(set1.mkString(","))
// 删除数据
set1.update(3,false)
println(set1.mkString(","))
// 删除数据
set1.remove(2)
println(set1.mkString(","))
// 遍历数据
set1.foreach(println)
}
}
集合取交集 差集
val set1 = mutable.Set(1, 2, 3, 4)
val set2 = mutable.Set(2,4, 5, 6, 7)
// 交集
val set3: mutable.Set[Int] = set1 & set2
println(set3.mkString(","))
// 差集
val set4: mutable.Set[Int] = set1 &~ set2
println(set4.mkString(","))
Map(映射)是一种可迭代的键值对(key/value)结构。所有的值都可以通过键来获取。Map 中的键都是唯一的。
不可变啊Map
无序的:
/ map描述了一个数据无序 key不可重复的集合
// scala中的kv键值对非常特殊
val map = Map(
"a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5
)
println(map)
key不可重复
val map = Map(
"a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5,"a" -> 6
)
println(map)
基本语法:
val map1 = Map( "a" -> 1, "b" -> 2, "c" -> 3 )
val map2 = Map( "d" -> 4, "e" -> 5, "f" -> 6 )
// 添加数据
val map3 = map1 + ("d" -> 4)
println(map1 eq map3) // false
// 删除数据
val map4 = map3 - "d"
println(map4.mkString(","))
val map5: Map[String, Int] = map1 ++ map2
println(map5 eq map1)
println(map5.mkString(","))
val map6: Map[String, Int] = map1 ++: map2
println(map6 eq map1)
println(map6.mkString(","))
// 修改数据
val map7: Map[String, Int] = map1.updated("b", 5)
println(map7.mkString(","))
// 遍历数据
map1.foreach(println)
基本操作:
val map1 = Map( "a" -> 1, "b" -> 2, "c" -> 3 )
val map2 = Map( "d" -> 4, "e" -> 5, "f" -> 6 )
// 创建空集合
val empty: Map[String, Int] = Map.empty
println(empty)
// 获取指定key的值 apply
val i: Int = map1.apply("c")
println(i)
println(map1("c"))
// 获取可能存在的key值 Option类型是专门为了解决空指针异常而设计的
val maybeInt: Option[Int] = map1.get("c")
// 判断key值是否存在
if ( !maybeInt.isEmpty ) {
// 获取值
println(maybeInt.get)
} else {
// 如果不存在,获取默认值
println(maybeInt.getOrElse(0))
}
// 获取可能存在的key值, 如果不存在就使用默认值
println(map1.getOrElse("c", 0))
可变map
// TODO Map集合 可变Map
val map1 = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
val map2 = mutable.Map("d" -> 4, "e" -> 5, "f" -> 6)
// 添加数据
map1.put("d", 4)
val map3: mutable.Map[String, Int] = map1 + ("e" -> 4)
println(map1 eq map3)
val map4: mutable.Map[String, Int] = map1 += ("e" -> 5)
println(map1 eq map4)
// 修改数据
map1.update("e", 8)
map1("e") = 8
// 删除数据
map1.remove("e")
val map5: mutable.Map[String, Int] = map1 - "e"
println(map1 eq map5)
val map6: mutable.Map[String, Int] = map1 -= "e"
println(map1 eq map6)
// 清除集合
map1.clear()
在Scala语言中,我们可以将多个无关的数据元素封装为一个整体,这个整体我们称之为:元素组合,简称元组。有时也可将元组看成容纳元素的容器,其中最多只能容纳22个
// TODO Tuple 元祖
// 创建元组,使用小括号
val tuple = (1, "zhangsan", 30)
// 根据顺序号访问元组的数据
println(tuple._1)
println(tuple._2)
println(tuple._3)
// 迭代器
val iterator: Iterator[Any] = tuple.productIterator
// 根据索引访问元素
println(tuple.productElement(0))
// 如果元组的元素只有两个,那么我们称之为对偶元组,也称之为键值对
val kv: (String, Int) = ("a", 1)
val kv1: (String, Int) = "a" -> 1
println(kv eq kv1)
map的底层是对偶元组
// 如果元祖中的元素只有2个 称之为对偶元组 也可以称之为键值对
val kv = (1, "a")
val map = Map(
(1, "a"), (2, "b"), (3, "c")
)
// 遍历
map.foreach(
t => {println(s"${t._1} = ${t._2}")}
)
队列:Scala也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为enqueue和dequeue。
object Scala_Collection09_Queue {
def main(args: Array[String]): Unit = {
// TODO Queue 队列
val que = new mutable.Queue[String]()
// 添加元素
que.enqueue("a", "b", "c")
val que1: mutable.Queue[String] = que += "d"
println(que eq que1)
// 获取元素
println(que.dequeue())
println(que.dequeue())
println(que.dequeue())
}
}
Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。
object Scala_Collection10_Par {
def main(args: Array[String]): Unit = {
// TODO 并行集合
val result1 = (0 to 100).map{x => Thread.currentThread.getName}
val result2 = (0 to 100).par.map{x => Thread.currentThread.getName}
println(result1)
println(result2)
}
}
// TODO 集合中常用的方法
val array = ArrayBuffer(1,2,3,4,2,4,5)
// 1、集合长度
println(array.size)
println(array.length)
// 2、判断集合是否为空
println(array.isEmpty) // false
// 3、判断集合是否包含某个元素
println(array.contains(2)) // true
// 4、去重
println(array.distinct.mkString(",")) // 12345
// 5、集合反转
println(array.reverse.mkString(",")) // 5424321
// 6、将集合转为字符串
println(array.mkString(","))
// 7、集合循环遍历
array.foreach(println)
// 8、集合迭代器
println(array.iterator)
衍生集合
object Scala_Collection03_Method2 {
def main(args: Array[String]): Unit = {
// TODO 集合中常用的方法
val array = ArrayBuffer(1,2,3,4)
// TODO 从集合中获取部分数据
// 1、获取第一个元素 集合头
println(array.head) // 1
// 2、集合尾
println(array.tail) // (2,3,4)
// 3、集合尾迭代器
println(array.tails) // 迭代器
// 4、最后一个元素 last
println(array.last) // 4
// 5、集合初始值
println(array.init) // (1,2,3)
// 6、集合初始迭代器
println(array.inits)
// TODO 取前几个元素
println(array.take(2)) // 取前两个 1,2
println(array.takeRight(2)) // 取后三个
// TODO 丢弃前几个元素
println(array.drop(1)) // 丢弃前一个元素
println(array.dropRight(1)) // 丢弃后一个元素
}
}
多数据集操作:
val list1 = List(1, 2, 3, 4)
val list2 = List(3, 4, 5, 6)
// 集合并集
println("union => " + list1.union(list2)) // 并集 合并在一起 12343456
// 集合交集
println("intersect => " + list1.intersect(list2)) // 交集 3,4
// 集合差集
println("diff => " + list1.diff(list2)) // 差集 去掉交集部分 1 2
滑动滚动窗口:
// 滑动窗口
println(list1.sliding(2).mkString(","))
// 滚动(没有重复) 第二个参数称之为滑动步长
println(list1.sliding(2,2).mkString(","))
拉链操作
// 拉链操作
println("zip => " + list1.zip(list2))
// 数据索引拉链 自身和索引尽心拉链
println("zipWithIndex => " + list1.zipWithIndex)
val array = ArrayBuffer(1,2,3,4)
// 1、求最大值
println(array.max)
// 2、求最小值
println(array.min)
// 3、求和
println(array.sum)
// 4、求乘积
println(array.product)
如果我们想要做其他运算操作呢?相除 相减
这里就需要我们自定义数据操作的方法,我们以相加为例
scala中提供了reduce集合简化规约的方法 传递的参数是一个函数
代码实现:
def reduceFun(x:Int,y:Int): Int ={
x + y
}
println(array.reduce(reduceFun))
太复杂 这里我们就可以使用我们熟悉的匿名函数了
集合简化规约左和集合简化规约右
val array2 = Array(1,2,3,4,5)
// 集合简化规约左
println(array2.reduceLeft(_ - _)) // -13
// 集合简化规约右
println(array2.reduceRight(_ - _)) // 3
查看底层源码
// 反转 [5,4,3,2,1]
// reduceleft y - x
// 1-(2-(3-(4-5))) = 3 所以结果为3
集合和外部的数据做聚合操作
object Scala_Collection03_Method4 {
def main(args: Array[String]): Unit = {
// TODO 集合 计算函数 聚合函数
val array = ArrayBuffer(1,2,3,4)
val num = 5
// 折叠 将集合外的数据 和集合内的元素做两两聚合
// fold 底层调用的是foldLeft
println(array.fold(num)(_ + _))
// foldLeft
// 5 [1,2,3,4]
// (((5-1)-2)-3)-4
println(array.foldLeft(num)(_ - _)) // -5
// foldRight
// 反转 5 [4,3,2,1]
// 1-(2-(3-(4-5))) = 3
println(array.foldRight(num)(_ - _)) // 3
// scan 记录计算的过程
println(array.scan(num)(_ - _))
println(array.scanRight(num)(_ - _))
}
}
功能函数:由集合对象提供的函数执行自定义的功能
val array = ArrayBuffer(1,2,3,4)
// 需求 将集合中的数据+2 3,4,5,6
// map映射 传递一个函数类型的参数即可 做具体的操作
println(array.map(_ + 2))
println(array.map(_ * 2))
扁平化:将整体拆分成个体
// 扁平化只对最外层起作用
val array = ArrayBuffer(
ArrayBuffer(1,2),ArrayBuffer(3,4)
)
println(array.flatten)
// 扁平化只对最外层起作用
val array = ArrayBuffer(
ArrayBuffer(ArrayBuffer(1,2),ArrayBuffer(3,4)),
ArrayBuffer(ArrayBuffer(5,6),ArrayBuffer(7,8))
)
println(array.flatten.flatten) // 调用两次
扁平化映射 相当于先map 再flatten
// 2、扁平化映射 先map 再flatten
val array1 = Array("java java scala spark","hello java scala spark")
// 需求 : 将字符串分解为一个一个的单词
println(array1.flatMap(str => str.split(" ")).mkString(","))
过滤函数 可以对集合中没一个数据进行筛选过滤
val array2 = ArrayBuffer(1,2,3,4)
// 需求:留下 偶数
println(array2.filter(num => {
num % 2 == 0
}))
// 至简原则
println(array2.filter(_ % 2 == 0))
val array3 = ArrayBuffer(1,2,3,4)
// 奇数一组 偶数一组
println(array3.groupBy(_ % 2))
分组小练习:将首字母一样的分一个组
println("------------------------小练习-----------------------")
val strArray = ArrayBuffer("scala","spark","java","javascript")
println(strArray.groupBy(word => word.substring(0, 1)))
println(strArray.groupBy(word => word.charAt(0)))
排序,通过指定的规则对每一条数据进行排序
val array4 = ArrayBuffer(1, 3, 2, 5, 7, 4)
// 通过指定的规则对数据进行排序 默认为升序
println(array4.sortBy(num => num))
// 降序 使用过函数的柯里化
println(array4.sortBy(num => num)(Ordering.Int.reverse)) // 降序
val array5 = ArrayBuffer("1", "22", "11", "2", "3")
println(array5.sortBy(s => s)) // 按照字典序 1 11 2 22 3
println(array5.sortBy(s => s.toInt)) // 按照数字排序 1 2 3 11 22
自定义排序
// 自定义排序 按元素大小升序排序
println(list1.sortWith((x, y) => x < y))
// 自定义排序 按元素大小降序排序
println(list1.sortWith((x, y) => x > y))