9 集合
Scala的集合有三大类:序列Seq、集Set、映射Map,所有集合都扩展自Iterable特质。对于所有的集合类,Scala都同时提供了可变和不可变的版本。
可变集合和不可变集合使用包名区分:scala.collection.immutable scala.collection.mutable
可变 | 不可变 | |
---|---|---|
数组 | Array | ArrayBuffer |
序列(List) | Seq、List | ListBuffer |
集合 | Set | mutable.Set |
映射 | Map | mutable.Map |
元组 | Tuple | \ |
9.1 数组
①数组的声明
scala中的数组在编译时其实就是编译为java中的数组
scala中数组的声明形式:方式1:只声明不初始化
//方式1:
val array1 : String = new Array[String](3)
//方式2:
val array2 : String = new Array(3)
//方式3:
val array3 = new Array[String](3)
scala中数组的声明形式:方式2:声明的同时初始化
object Test01_Collection_Array_2 {
def main(args: Array[String]): Unit = {
//TODO 创建数组的同时进行初始化
//Java中:String[] array = new String[]{"Tom", "Jerry"};
//伴生对象(参数) => 伴生对象.apply(参数)
val array = Array(1, 2, 3, 4)
val array1 : Array[Int] = Array(10, 12, 13, 14)
//更新数组中的值
// array(2) = 6
array.update(2, 5)
//将一个数组加在另一个数组上
val array2 = array.++(array1) //将array1加在后面
val array3 = array1 ++: array //将array1加在前面
println(array3.mkString(","))
}
}
②数据的访问:
object TestArray {
def main(args: Array[String]): Unit = {
//方式1:
val array1 : Array[String] = new Array[String](3)
//方式2:
val array2 : Array[String] = new Array(3)
//方式3:
val array3 = new Array[String](3)
//数据访问
//scala中中括号用来表示泛型,使用小括号来表示数组索引位置
array1(0) = "Tom"
array1(1) = "Jerry"
//数组的遍历
//方式1:
for(a <- array1){
println(a)
}
//方式2:
println(array1.mkString(","))
//方式3:foreach方法就是为了遍历数据,所以将循环的每一个数据传递到处理函数中
array1.foreach((s:String) => println(s))
array1.foreach(println(_))
array1.foreach(println)
}
}
③不可变
scala默认的集合都是不可变的,当添加数据时,会生成一个新的集合
不可变数组,1 添加数据到数组的前面:
5 +: array 或者 array.+:(5)
2 添加数据到数组的后面:
array :+ 5
3 添加数组到数组的后面
array ++ array1 或者 array.++(array1)
array1 ++ array 或者 array1.++(array)
object TestArray1 {
def main(args: Array[String]): Unit = {
//TODO 数组不可变
//scala中默认的集合都是不可变的
val array = new Array[String](3)
array(0) = "Tom"
//添加数据
//scala默认的集合都是不可变的,当添加数据时,会生成一个新的集合
//scala中如果不采用方法调用,而是采用运算符的方式调用的话
//如果这个运算符以冒号结尾,那么运算规则为从右向左执行
// val array1 = array.+:("Jerry") //加载数组前面
val array1 = "Jerry" +: array //加载数组前面
// val array1 = array :+ "Jerry" //加载数组后面
// val array1 = array +: "Jerry" //将Jerry的每一个元素加载数组后面
println(array1.mkString(","))
}
}
基本操作:
object Test01_Collection_Array_3 {
def main(args: Array[String]): Unit = {
val array = Array(1, 2, 3, 4)
val array1: Array[Int] = Array(4, 5, 6, 7, 8)
//1 添加数组元素,创建新的数组
val array2 = array :+ 5
//2 添加集合
val array3 = array ++ array1
val array4 = array ++: array1
//3 合并数组
val array6 = Array.concat(array, array1)
// println(array6.mkString(","))
//4 创建指定范围的数组
val array7 = Array.range(0, 2)
println(array7.mkString(",")) //0,1
//5 创建并填充指定数量的数组(可以创建多维数组)
val array8 = Array.fill[Int](5, 2)(-1)
// println(array8.mkString(","))
array8.foreach(arr => println(arr.mkString(",")))
//6 多维数组
val array5 = Array.ofDim[Int](3, 5)
array5.foreach(list => println(list.mkString(",")))
}
}
④ 可变数组ArrayBuffer
默认初始化长度为16
object Test01_Collection_ArrayBuffer {
def main(args: Array[String]): Unit = {
//默认情况下,scala提供的集合数组不可变,但是也提供了可变的集合数组ArrayBuffer
//集合中,创建集合最常见的方法是伴生对象的apply()
//伴生类的方式创建可变数组
val buffer = new ArrayBuffer[String]()
//伴生对象创建可变数组
val buffer1 = ArrayBuffer(1, 2, 3, 4)
val buffer2 = ArrayBuffer(5, 6, 7, 8)
//1 增加数据
//可变数组,增加数据可以对原来的集合进行改变
buffer1.append(5)
buffer1.insert(1, 6)
//添加集合
buffer1.appendAll(buffer2)
//2 修改数据
buffer1.update(1, 100)
//3 删除数据
buffer1.remove(1)
//删除从索引为1后面的4个数据
buffer1.remove(1, 4)
//4 遍历数据
buffer1.foreach(println(_))
println(buffer1.mkString(","))
println(buffer1)
//5 不可变集合的操作都使用运算符
//可变集合的操作都使用方法
buffer1+=4 //加在后面
44 +=: buffer1 //加在前面
println(buffer1)
}
}
⑤ 可变和不可变数组的转换
object Test01_Collection_ArrayBuffer_1 {
def main(args: Array[String]): Unit = {
// val array = new Array[Int](4)
val array = Array(1, 2, 3, 4)
val buffer = ArrayBuffer(1, 2, 3, 4)
//可变 => 不可变
val buffer1: mutable.Buffer[Int] = array.toBuffer
//不可变 => 可变
val array1: Array[Int] = buffer.toArray
}
}
9.2 序列Seq(List)
①不可变
object Test01_Collection_Seq {
def main(args: Array[String]): Unit = {
//TODO 集合-序列Seq(List)
//List:有序的,数据可重复的
val seq = Seq(1, 2, 3, 4)
//在使用序列的集合时,使用的最多的为List
//构建不可变的序列集合
val list = List(1, 2, 3, 4)
//5 是加在集合的后面
val list1 = list :+ 5
//6 是加在集合的前面
val list2 = 6 +: list
println(list)
println(list2)
//创建List空集合
//空集合
val nil = Nil
// println(nil)
//向空集合中添加数据
println(1::2::3::4::Nil)
val list3 = List(9, 9, 9, 9)
//将一个list集合作为整体添加到空集合中
println(1::2::3::4::list3::Nil) //List(1, 2, 3, 4, List(9, 9, 9, 9))
//将整体拆分成一个一个的个体来使用,称为扁平化
println(1::2::3::4::list3:::Nil) //List(1, 2, 3, 4, 9, 9, 9, 9)
}
}
②可变的序列ListBuffer
object Test01_Collection_Seq_1 {
def main(args: Array[String]): Unit = {
val buffer = ListBuffer(1, 2, 3, 4)
buffer.append(5)
buffer.appendAll(List(1,1,1))
buffer.insert(1, 6)
buffer.update(1, 6)
buffer.remove(2)
buffer.remove(1, 3)
buffer.foreach(println)
println(buffer.mkString(","))
}
}
9.3 集合Set
①可变集合Set
object Test01_Collection_Set_1 {
def main(args: Array[String]): Unit = {
//TODO 不可变集合Set
val set = Set(1, 2, 3, 4, 5, 6, 7)
//1 添加元素
//不可变集合Set不支持添加修改,可以删除和添加,但是是生成新的Set
val set1 = set + 10
val set2 = set.+(11, 12)
println(set)
println(set1)
println(set2)
//2 删除元素
val set3 = set - 10
println(set3)
//3 遍历集合Set
set.foreach(println)
println(set.mkString(","))
}
}
②不可变集合Set
Set本身是无序的,不可变的;如果使用mutable.Set,这样的Set集合就是可变的了。但是还是不能重复,且无序。
object Test01_Collection_Set_2 {
def main(args: Array[String]): Unit = {
//TODO 可变集合mutable.Set
val set = mutable.Set(1, 2, 3, 4, 5, 6, 7)
//1 添加数据,可变集合mutable.Set是在原集合的基础上添加数据
set.add(10)
//update(11, true),表示在set中添加11这个元素,
//update(1, false),表示从set中排除1这个元素
set.update(11, true)
//2 删除数据
//set.remove(1) 等同于 update(1, false)
set.remove(1)
//3 遍历集合
set.foreach((x:Int)=>{println(x)})
set.foreach(println(_))
set.foreach(println)
//4 生成字符串
println(set.mkString(","))
val set1 = mutable.Set(1, 2, 3, 4, 5)
val set2 = mutable.Set(3, 4, 5, 6, 7, 8)
//5 交集
val set3 = set1 & set2
//6 差集
val set4 = set1 &~ set2
println(set)
}
}
9.4 映射Map
Map存储的是k-v,声明形式有:Map(“a”->1, “b”->2, “c”->3)和:Map((“a”, 1), (“b”, 2), (“c”, 3))
Map的key不能重复,并且key是无序的。但是value可以重复。
①不可变Map
object Test01_Collection_map_1 {
def main(args: Array[String]): Unit = {
//TODO 集合-映射转换(Map)
// TODO 不可变集合Map
//Map初始化方式1:
val map = Map("a" -> 1, "b" -> 2, "c" -> 3)
//Map初始化方式2:以元组的方式
val map1 = Map(("aa", 11), ("bb", 22), ("cc", 33))
//1 添加数据,因为map是不可变的,所以生成新的Map
val map3 = map + ("ee" -> 10)
val map2 = map1 + (("ee", 10))
println(map2)
println(map3)
//2 修改数据,Map不可变,所以是生成新的Map
val map4 = map.updated("a", 100)
println(map)
println(map4)
//3 删除数据,Map不可变,生成新的Map
val map5 = map - "a"
println(map5)
//4 遍历Map
map.foreach(println)
//5 创建空Map
val empty = Map.empty
println(empty)
//6 获取Map的指定key的value值
println(map("a"))
//7 获取可能的key值
val maybeInt: Option[Int] = map.get("b")
//判断key值是否存在;不存在None;存在Some(value值)
println(maybeInt)
//8 获取可能存在的值,如果不存在就使用默认的值
println(map.getOrElse("aaa", 11))
}
}
②可变Map
import scala.collection.mutable
object Test01_Collection_map_2 {
def main(args: Array[String]): Unit = {
//TODO 集合-映射转换(Map)
// TODO 可变Map
val map = mutable.Map(("a", 1), ("b", 2), ("c", 3))
//1 增加数据,mutable.Map是可变的Map,所以原Map会被修改
map.put("d", 4)
//2 查询数据
val maybeInt: Option[Int] = map.get("c")
//选项类型Option,为了避免出现null值,取到值:Some(value值);没取到值:None
if (maybeInt.isEmpty){
println("要查找的数据不存在")
}else{
println(maybeInt.get)
}
//3 修改数据
map.update("a", 11)
//4 删除数据
map.remove("a")
//5 Map转List
val list = map.toList
println(list)
//6 遍历Map,转成String
println(map.mkString(","))
//遍历values
println(map.values.mkString(","))
//遍历keys
println(map.keys.mkString(","))
//7 Map的迭代器
val iterator = map.iterator
while (iterator.hasNext){
println(iterator.next())
}
//Map的key的迭代器
val iterator1 = map.keysIterator
val iterator2 = map.keys.iterator
//Map的value的迭代器
val iterator3 = map.valuesIterator
val iterator4 = map.values.iterator
//8 Map的foreach
map.foreach(println)
//9 清除Map
map.clear()
println(map)
}
}
9.5 元组 Tuple
object Test01_Collection_tuple {
def main(args: Array[String]): Unit = {
//TODO 元组
//scala中将无关的数据作为一个整体来使用,形成了一个元素的数据组合,简称为元组(Tuple)
//scala中元组使用小括号声明
//元组的类型
//元组的类型最多只能容纳22个
//只是限制了数据容纳的个数,没有限制数据容纳的类型
val tuple: (Int, String, Char, Double) = (1, "Tom", 'a', 22.2)
//元组数据的访问
//根据有效的序号访问
println(tuple._1)
println(tuple._2)
println(tuple._3)
println(tuple._4)
//1 采用数据在元组中的索引访问
println(tuple.productElement(1))
//2 采用迭代器的方式访问
val iterator = tuple.productIterator
while (iterator.hasNext){
println(iterator.next())
}
}
}
- 元组中只有2个元素,那么这样的元素称为对偶元组,也成为键值对
object Scala06_Collection_Tuple_1 {
def main(args: Array[String]): Unit = {
// TODO 集合 - 元组
// 如果元组中只有2个元素,那么这样的元组称之为对偶元组,也称之为键值对
//val kv = ("a", 1)
// map集合中的键值对其实就是元组
//val tuple: ((String, String), Int) = "a" -> "b" -> 1
val map = Map( ("a", 1), ("b", 2), ("c", 3) )
for ( kv <- map ) {
println(kv._1 + "," + kv. _2)
}
}
}
- 元组中的每一个元素不能更改
object Scala06_Collection_Tuple_2 {
def main(args: Array[String]): Unit = {
// TODO 集合 - 元组
// 元组中的每一个元素不能被更改
val t = (1, "zhangsan", 30)
//t._1 = 2
}
}
9.6 队列
import scala.collection.mutable
object Scala07_Collection_Queue {
def main(args: Array[String]): Unit = {
// TODO 集合 - 队列
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())
}
}
①kafka中如何保证消费数据的有序?
- 1 分区间无序,分区内有序(保存数据有序)
- 2 生产者端采用双端队列(生产数据有序)
9.7 并行
import scala.collection.mutable
object Scala08_Collection_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)
}
}
①串行 & 并行 & 并发
10 常用方法
10.1 常用方法
object ScalaCollection{
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
// 1 集合长度
println("size =>" + list.size)
println("length =>" + list.length)
// 2 判断集合是否为空
println("isEmpty =>" + list.isEmpty)
// 3 集合迭代器
println("iterator =>" + list.iterator)
// 4 循环遍历集合
list.foreach(println)
// 5 将集合转换为字符串
println("mkString =>" + list.mkString(","))
// 6 判断集合中是否包含某个元素
println("contains =>" + list.contains(2))
// 7 取集合的前几个元素
println("take =>" + list.take(2))
// 8 取集合的后几个元素
println("takeRight =>" + list.takeRight(2))
// 9 查找元素
println("find =>" + list.find(x => x % 2== 0))
// 10 丢弃前几个元素
//mutable.List 丢弃后几个为什么不会改变原数组???
//这是因为drop和去重都是产生新的数组,如果想删除原数组元素,可以使用remove
println("drop =>" + list.drop(2))
// 11丢弃后几个元素
println("dropRight =>" + list.dropRight(2))
// 12 反转集合
println("reverse =>" + list.reverse)
// 13 去重
println("distinct =>" + list.distinct)
}
}
10.2 衍生集合
object ScalaCollection{
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
val list1 = List(1,2,3,4)
val list2 = List(3,4,5,6)
// 1 集合头
println("head => " + list.head)
// 2 集合尾
println("tail => " + list.tail)
// 3 集合尾迭代
println("tails => " + list.tails)
// 4 集合初始值
println("init => " + list.init)
// 5 集合初始值迭代
println("inits => " + list.inits)
// 6 集合最后元素
println("last => " + list.last)
// 7 集合并集
println("union => " + list.union(list1))
// 8 集合交集
println("intersect => " + list.intersect(list1))
// 9 集合差集
println("diff => " + list.diff(list1))
// 10 切分集合
//切分集合怎么切分的??
//splitAt(n),切成两个,第一个集合的数量就是n,第二个几个的数量是剩下的
println("splitAt => " + list.splitAt(2))
// 滑动(窗口)
println("sliding => " + list.sliding(2))
// 滚动(没有重复)
println("sliding => " + list.sliding(2,2))
// 拉链
//如果一个List的数量多另一个List的数量少,另一个就没有了
println("zip => " + list.zip(list1))
// 数据索引拉链,结果是(数据,索引)
println("zipWithIndex => " + list.zipWithIndex)
}
}
10.3 计算函数
object Function3 {
def main(args: Array[String]): Unit = {
//TODO 计算函数
val list = List(1, 2, 3, 4)
val list1 = List(6, 7, 8, 9)
val set = mutable.Set(2, 3, 5, 3)
val map = mutable.Map(("a", 1),("a", 1),("d", 11), ("b", 2), ("c", 3))
// 1 集合的最小值
println(list.min)
println(set.min)
println(map.min)//TODO map的最小值和最大值,好像是根据key的大小??
//2 集合的最大值
println(list.max)
println(set.max)
println(map.max)
//3 集合求和
println(list.sum)
println(set.sum)
//TODO map的sum函数怎么用???
//4 集合乘积
println(list.product)
println(set.product)
//TODO map的product函数怎么用???
//5 集合简化规约reduce
println(list.reduce((x: Int, y: Int) => {
x - y
}))
println(set.reduce(_ + _))
//6 集合简化规约(左) 就等同于reduce (((1 - 2) - 3) - 4) = -8
println(list.reduceLeft(_ - _))
//7 集合简化规约(右) (1 - (2 - (3 - 4))) = -2
println(list.reduceRight(_ - _))
//8 集合折叠(函数柯里化)
//fold方法存在两个参数列表
//第一个参数列表中的参数表示计算的初始值
//第二个参数列表中的参数表示以第一个参数为基准,两两计算的逻辑
println(list.fold(6)(_ - _))
//9 就等同于fold()()
println(list.foldLeft(6)(_ - _)) //((((6 - 1) - 2) - 3) - 4) = -4
//10 从右边折叠
println(list.foldRight(6)(_ - _)) // (1 - (2 - (3 - (4 - 6)))) = 4
//11 集合扫描
//scan方法会保留所有的计算过程的数据
println(list.scan(6)(_ - _))
//12 scanLeft
println(list.scanLeft(6)(_ - _))
//13 scanRight
println(list.scanRight(6)(_ - _))
}
}
10.4 功能函数
object Function4 {
def main(args: Array[String]): Unit = {
//TODO 功能函数
val list = List(1, 2, 3, 4, 5)
val map = mutable.Map(("a", 1), ("b", 2), ("c", 3))
//1 集合映射map
list.map((x: Int) => println(x * 2))
println(list.map(_ * 2))
//2 集合扁平化flatten
//将集合整体拆分成一个个的个体来使用。
val buffer = ListBuffer(List(1, 2, 3, 4), List(4, 8, 7, 6))
println(buffer.flatten)
val set = mutable.Set(List(1, 2, 3, 4), List(3, 4, 9, 8))
println(set.flatten)
//flatten只能拆除外层包装:
val list1 = List(List(List(1, 2, 3)), List(List(1, 1)))
println(list1.flatten) //List(List(1, 2, 3), List(1, 1))
println(list1.flatten.flatten) //List(1, 2, 3, 1, 1)
//3 自定义扁平化flatMap
val list2 = List("hello world scala", "hello spark")
val words = list2.flatMap(s => {
val word = s.split(" ")
word
})
println(words.mkString(","))
//4 集合过滤数据filter
println(list.filter((x: Int) => {
x % 2 == 0
}))
println(list.filter(_ % 2 == 0))
//5 集合分组数据groupBy
//分组后,返回的结果是Map类型,key是分组的K,value是符合分组K的数据集合
val list3 = List("hello","world","scala","hello","spark")
val groupMap = list3.groupBy((s: String) => {
s.substring(0, 1)
})
println(groupMap) //Map(w -> List(world), h -> List(hello, hello), s -> List(scala, spark))
//6 集合排序sortBy
//对上面的结果,统计w和h和s开头的单词的个数,然后排序
val sumList = groupMap.toList.map(t => {
val size = t._2.size
(t._1, size)
})
println(sumList)
//排序默认是升序排序
//更改为降序排序使用.Ordering.Int.reverse
println(sumList.sortBy(t => t._2))
println(sumList.sortBy(t => t._2)(Ordering.Int.reverse))
}
}