一、集合简介
1. 类型
- 序列 Seq:类似于 Java 中的 List 接口
- 集 Set:类似于 Java 中的 Set 接口
- 映射 Map:类似于 Java 中的 Map 接口
- 所有的集合都扩展自 Iterable 特质
2. 不可变集合
位于 scala.collection.immutable 包,指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 Java 中的 String 对象
- Scala 中的 Array 和 String 类本质是使用 type 关键字为 Java 中对应类所设置的别名
- Array 和 String 类本身并没有 extends IndexedSeq,Array 和 String 类使用时实际是被隐式转换成了 WrappedArray 和 WrappedString 类,而 WrappedArray 和 WrappedString 类继承了 IndexedSeq 特质
- IndexedSeq 和 LinearSeq 的区别:
- IndexedSeq 是通过索引来查找和定位,所以查询速度快,比如 String 就是一个索引集
- LinearSeq 是线型的,即有头尾的概念,所以增删效率高,一般是通过遍历来查找,查询效率低
3. 可变集合
位于 scala.collection.mutable 包,指该集合对象可以直接对原对象进行修改,而不会返回新的对象。类似于 Java 中 StringBuilder 对象
- 在操作不可变集合的时建议使用符号类方法
- 在操作可变集合的时建议使用名称类方法
二、Seq 集合之数组
1. 不可变数组
1.1 创建
object TestImmutableArray {
def main(args: Array[String]): Unit = {
// 方式一
/*
Array[Int] 表示存储元素类型为 Int 的数组
(10) 表示数组最大元素个数为 10
*/
val arr1: Array[Int] = new Array[Int](10)
// 方式二
/*
Array() 本质是调用伴生对象的 apply() 方法
*/
val arr2: Array[Int] = Array(10, 20, 30, 40)
}
}
1.2 操作
object TestImmutableArray {
def main(args: Array[String]): Unit = {
// 创建数组
val arr: Array[Int] = Array(10, 20, 30, 40)
// 1. 访问某个元素
val i: Int = arr(0) // 底层是 Array 类的存根方法 apply(i: Int)
println(i)
// 2. 修改某个元素值(不可变数组是对象地址和容量不能改变,元素值可以修改)
println(arr(1))
arr(1) = 50 // 底层是 Array 类的存根方法 update(i: Int, value: T)
println(arr(1))
// 3. 遍历数组
// 3.1 普通 for 循环 + 索引
for(i <- 0 util arr.length) println(arr(i))
for(i <- arr.indices) println(arr(i))
// 3.2 普通 for 循环 + 元素,类似 Java 的增强 for 循环
for(elem <- arr) println(elem)
// 3.3 迭代器
val iterator = arr.iterator()
while(iterator.hasNext) println(iterator.next)
// 3.4 foreach 方法:foreach(func: a => b)
arr.foreach(println)
// 3.5 所有元素整体以字符串打印
println(arr.mkString(","))
// 4. 添加元素(得到新数组)
/*
:+() 方法底层是先获取原数组的长度,再创建一个大小为原数组长度+1的新数组,将原数组的元素
copy 到新数组,最后将添加的值赋值给最后一个元素
+:() 方法是向前添加元素
*/
val newArr1 = arr.:+(20)
val newArr2 = newArr1.+:(8)
println(arr.mkString("-")) // arr 没有改变
println(newArr1.mkString("-"))
println(newArr2.mkString("-"))
// 简写
val newArr3 = arr :+ 20
val newArr4 = 8 +: arr
println(arr.mkString("-"))
println(newArr3.mkString("-"))
println(newArr4.mkString("-"))
val newArr5 = 2 +: 6 +: arr :+ 50 :+ 60
println(newArr5.mkString("-"))
}
}
2. 可变数组
ArrayBuffer 类
2.1 创建
object TestMutableArray {
def main(args: Array[String]): Unit = {
// 方式一
/*
ArrayBuffer[Int] 表示元素类型为 Int 的可变数组,[Int] 可以省略,元素类型为 Any
() 可以不指定元素最大个数,调用的是辅助构造器,默认大小为 16
*/
// 需要导包
import scala.collection.mutable.ArrayBuffer
val arr1: ArrayBuffer[Int] = new ArrayBuffer[Int]()
// 方式二
val arr2: ArrayBuffer[Int] = ArrayBuffer(10, 20, 30, 40)
println(arr2) // ArrayBuffer(10, 20, 30, 40),调用 arr2.toString()
}
}
2.2 操作
object TestMutableArray {
def main(args: Array[String]): Unit = {
// 创建数组
val arr: ArrayBuffer[Int] = ArrayBuffer(10, 20, 30, 40)
// 1. 访问元素
println(arr(1))
// 2. 修改元素值
println(arr(0))
arr(0) = 8
println(arr(0))
// 3. 遍历数组,同不可变数组遍历
// 4. 添加元素
// 4.1 符号类方法(不可变集合推荐)
arr += 50 // 末尾追加
println(arr)
arr +=: 8 // 开头添加
println(arr)
// 4.2 名称类方法(可变集合推荐)
arr.append(60, 70) // 末尾追加多个元素
// arr.appendAll(ArrayBuffer(4, 5, 6))
println(arr)
arr.prepend(4, 6) // 开头添加多个元素
// arr.prependAll(ArrayBuffer(4, 5, 6))
println(arr)
arr.insert(3, 11, 14) // 在指定下标位置添加多个元素
println(arr)
arr.insertAll(2, ArrayBuffer(4, 5, 6)) // 在指定下标位置添加一个数组
println(arr)
// 5. 删除元素
arr.remove(1) // 删除下标为 1 的元素
println(arr)
arr.remove(3, 3) // 删除下标 3 及往后的 2 个元素
println(arr)
arr -= 40 // 删除元素 40,不存在无操作
println(arr)
}
}
3. 不可变与可变转换
object TestArrayTransform {
def main(args: Array[String]): Unit = {
// 1. 可变数组转不可变数组:toArray
val muArr: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)
val immuArr: Array[Int] = muArr.toArray
println(muArr)
println(immuArr)
// 2. 不可变数组转可变数组:toBuffer
val immuArr1: Array[Int] = Array(4, 5, 6)
val muArr1: mutable.Buffer[Int] = immuArr1.toBuffer
println(immuArr1)
println(muArr1)
}
}
4. 多维数组
4.1 创建
object TestMultiArray {
def main(args: Array[String]): Unit = {
/*
Array.ofDim[Int] 表示创建指定维度的元素类型为 Int 的数组
(2, 3) 表示数组维度为 2 行 3 列,即该多维数组有 2 个数组元素,每个数组元素有 3 个元素
*/
val mulArray: Array[Array[Int]] = Array.ofDim[Int](2, 3)
}
}
4.2 操作
object TestMultiArray {
def main(args: Array[String]): Unit = {
// 创建多维数组
val mulArray: Array[Array[Int]] = Array.ofDim[Int](2, 3)
// 1. 访问元素
println(mulArray(0)(1))
// 2. 修改元素值
mulArray(1)(2) = 10
mulArray(0)(0) = 30
// 3. 遍历多维数组
for(i <- mulArray.indices; j <- mulArray(i).indices) {
if(j == mulArray(i).length -1) println() else println(mulArray(i)(j) + "\t")
}
mulArray.foreach(_.foreach(println))
}
}
三、Seq 集合之List
1. 不可变 List
1.1 创建
object TestList {
def main(agrs: Array[String]): Unit = {
// 1. 使用伴生对象的 apply 方法(由于 List 是 sealed abstract class,不能使用 new)
// sealed class 密封类,与这个类所有相关的对象和子类必须都定义在同一个源文件.scala 中
val list1: List = List(10, 20, 30)
// 2. 使用空集合、:: 方法 和 :: 类创建
// Nil 是继承 List 的一个 case object
// :: 方法 是 List 类中的一个方法,实现是创建并返回一个 :: 类
// :: 类,是继承 List 的一个 case class
val list2 = 10 :: 20 :: 30 :: Nil
}
}
1.2 操作
object TestList {
def main(agrs: Array[String]): Unit = {
// 创建 List
val list1: List = List(10, 20, 30)
// 1. 访问和遍历元素
println(list1(1)) // 虽然 LinearSeq 没有索引,但为了方便操作底层做了优化
list1.foreach(println)
// list(1) = 13 // error,不能使用索引方式修改
// 2. 添加元素
// 2.1 使用 +: 和 :+
val list2 = list1 :+ 40 // 尾部添加
println(list2)
val list3 = 8 +: list1 // 头部添加
println(list3)
// 2.2 使用 :: 方法头部添加
val list4 = 4 :: 6 :: 8 :: list1
println(list4)
// 3. 合并列表,也称为扁平化
// 3.1 使用 ::: 方法
val list5 = list2 ::: list3 // list3.:::(list2)
println(list5)
// 3.2 使用 ++ 方法,内部也是调用 ::: 方法
val list6 = list2 ++ list3
println(list6)
}
}
2. 可变 ListBuffer
2.1 创建
object TestListBuffer {
def main(args: Array[String]): Unit = {
// 1. 使用 new 创建
val list1: ListBuffer[Int] = new ListBuffer[Int]()
// 2. 使用伴生对象的 apply 方法
val list2 = ListBuffer(10, 20, 30)
}
}
2.2 操作
object TestListBuffer {
def main(args: Array[String]): Unit = {
// 创建
val list1 = ListBuffer(10, 20, 30)
// 1. 访问元素
println(list1(0))
// 2. 修改元素
print(list1(1))
list1(1) = 22 // 底层是调用 list1.update(1, 22) 方法
print(list1(1))
// 3. 添加元素
// 3.1 使用 += 和 +=:
list1 += 40 += 50
println(list1)
6 +=: 8 +=: list1 += 60
println(list1)
// 3.2 使用 append/appendAll/prepend/prependAll/insert/insertAll
list1.append(66, 68)
println(list1)
list1.prepend(2, 4)
println(list1)
list1.insert(1, 3, 4)
println(list1)
// 4. 合并列表
// 4.1 使用 ++ (返回新列表,操作的列表不改变)
val list2 = ListBuffer(2, 3, 4)
println(list1)
println(list2)
println("================")
val list3 = list1 ++ list2
println(list1)
println(list2)
println(list3)
// 4.2 使用 ++=/++=: (调用方法的列表改变,参数列表不改变)
val list4 = ListBuffer(2, 3, 4)
println(list1)
println(list4)
println("================")
list1 ++= list4
println(list1)
println(list4)
// 5. 删除元素
list1.remove(2) // 删除索引 2 位置元素
println(list1)
list1 -= 10 // 删除值为 10 的元素
println(list1)
}
}
四、Set 集合
1. 不可变 Set
1.1 创建
object TestImmutableSet {
def main(args: Array[String]): Unit = {
// 使用伴生对象 apply 方法创建(Set 是 trait,不能使用 new)
val set1 = Set(11, 11, 12, 13, 14, 14, 15) // 无序无重复
println(set1) // 去除重复值
}
}
1.2 操作
object TestImmutableSet {
def main(args: Array[String]): Unit = {
// 创建
val set1 = Set(11, 11, 12, 13, 14, 14, 15)
// 1. 添加元素
val set2 = set1 + 10 // set1.+(10)
println(set1) // set1 不改变
println(set2)
// 2. 合并集合
val set3 = Set(6, 11, 12, 13, 8, 4)
val set4 = set1 ++ set3
println(set1)
println(set3)
println(set4)
// 3. 删除元素
val set5 = set3 - 4 // set3.-(4)
println(set3)
println(set5)
// 4. 遍历
set1.foreach(println)
for(elem <- set1) println(elem)
}
}
2. 可变 mutable.Set
2.1 创建
object TestMutableSet {
def main(args: Array[String]): Unit = {
// 导入可变集合包
import scala.collection.mutable
// 使用伴生对象创建
val set1: mutable.Set[Int] = mutable.Set(11, 11, 12, 13, 14, 14, 15)
println(set1)
}
}
2.2 操作
import scala.collection.mutable
object TestMutableSet {
def main(args: Array[String]): Unit = {
// 创建
val set1: mutable.Set[Int] = mutable.Set(11, 11, 12, 13, 14, 14, 15)
// 1. 添加元素
// 1.1 使用 +=
set1 += 10
println(set1)
// 1.2 使用 add,底层调用 +=,返回值为 boolean,!set.contains(elem)
val res1 = set1.add(10) // false
println(set1)
val res2 = set1.add(8) // true
println(set1)
// 2. 删除元素
// 1.1 使用 -=
set1 -= 10
println(set1)
// 1.2 使用 remove,底层调用 -=,返回值为 boolean,set.contains(elem)
val res1 = set1.remove(10) // false
println(set1)
val res2 = set1.remove(8) // true
println(set1)
// 3. 合并集合
val set2 = mutable.Set(2, 2, 3, 4, 4, 5)
println(set1)
println(set2)
set1 ++= set2 // 调用者发生改变
println(set1)
println(set2) // 不改变
}
}
五、Map 集合
Scala 中的 Map 和 Java 类似, 也是一个散列表,它存储的内容也是键值对(key-value)映射,可以转化成二元组的集合
1. 不可变 Map
1.1 创建
object TestImmutableMap {
def main(args: Array[String]): Unit = {
// Map 是一个 trait,使用伴生对象的 apply 方法
val map1: Map[String, Int] = Map("a" -> 10, "b" -> 20, "hello" -> 30)
println(map1)
println(map1.getClass)
}
}
1.2 操作
object TestImmutableMap {
def main(args: Array[String]): Unit = {
// 创建
val map1: Map[String, Int] = Map("a" -> 10, "b" -> 20, "hello" -> 30)
// 1. 访问 key 对应的值
// 1.1 使用 get()
// Option 是一个密封抽象类,其子类有 Some 和 None
val value1: Option = map1.get("a") // Some(10)
println(value1.get)
val value2: Option = map1.get("c") // None
// println(value2.get) // error
// 1.2 使用 getOrElse()
val value3 = map1.getOrElse("c", 0) // 如果 key 不存在,就返回默认值 0
// 1.3 使用 map(key)
println(map1("a")) // 存在即获取值,不存在则抛异常,底层实现是 get() 加模式匹配
// 2. 遍历Map
// 2.1 foreach
map1.foreach(println) // 打印 KV 元组
map1.foreach( kv: (String, Int) => println(kv) ) // 等价于foreach(println)
// 2.2 for 循环
for(key <- map1.keys) {
println(s"$key -> ${map1.get(key).get}")
}
}
}
2. 可变 mutable.Map
2.1 创建
object TestMutableMap {
def main(args: Array[String]): Unit = {
// 导入可变集合的包
import scala.collection.mutable
// 使用伴生对象的 apply 方法创建
val map1: mutable.Map[String, Int] = mutable.Map("a" -> 10, "b" -> 20, "hello" -> 30)
println(map1)
println(map1.getClass) // HashMap
}
}
2.2 操作
import scala.collection.mutable
object TestMutableMap {
def main(args: Array[String]): Unit = {
// 创建
val map1 = mutable.Map("a" -> 10, "b" -> 20, "hello" -> 30)
// 1. 访问 key 对应的值
// 1.1 使用 get()
// Option 是一个密封抽象类,其子类有 Some 和 None
val value1: Option = map1.get("a") // Some(10)
println(value1.get)
val value2: Option = map1.get("c") // None
// println(value2.get) // error
// 1.2 使用 getOrElse()
val value3 = map1.getOrElse("c", 0) // 如果 key 不存在,就返回默认值 0
// 1.3 使用 map(key)
println(map1("a")) // 存在即获取值,不存在则抛异常,底层实现是 get() 加模式匹配
// 2. 添加元素
// 2.1 使用 +=
map1 += (("c", 7))
println(map1)
// 2.2 使用 put
map1.put("d", 16) // 底层调用的 update(k, v), update 底层调用 +=
println(map1)
// 3. 删除元素
// 3.1 使用 -=
map1 -= "c"
println(map1)
// 3.2 使用 remove
map1.remove("d") // 底层调用的 -=
println(map1)
// 4. 修改元素
map1.update("c", 7) // key 不存在则相当于 put
println(map1)
map1.update("a", 8) // key 存在则修改值
println(map1)
// 5. 合并map
val map2 = Map("aaa" -> 10, "b" -> 28, "hello" -> 40)
map1 ++= map2
println(map1) // 将 map2 中的元素覆盖或添加到 map1
println(map2) // map2 不改变
val map3: Map[String, Int] = map2 ++ map1
println(map3)
}
}
六、元组
元组可以理解为一个容器,可以存放各种相同或不同类型的数据,即将多个无关的数据封装为一个整体,称为元组
1. 创建
object TestTuple {
def main(args: Array[String]): Unit = {
// 元组中最大只能有 22 个元素(Tuple1~22)
val tuple: (String, Int, Char, Boolean) = ("hello", 10, 'a', true)
println(tuple)
}
}
2. 操作
object TestTuple {
def main(args: Array[String]): Unit = {
// 创建
val tuple: (String, Int, Char, Boolean) = ("hello", 10, 'a', true)
// 1. 访问元素
// 1.1 使用 _n
println(tuple._1) // 四个元素分别为 _1, _2, _3, _4
// 1.2 使用 productElement(index)
println(tuple.productElement(0)) // 索引从 0 开始
// 2. 遍历元组
for(elem <- tuple.productIterator) {
println(elem)
}
// 3. Map 与元组的关系
/*
Map 的每一个键值对是一个二元组(Tuple2),也称为对偶元组
*/
val map1 = Map("a" -> 10, "b" -> 20, "c" -> 30)
// 等价于
val map2 = Map(("a", 10), ("b", 20), ("c", 30))
// 4. 嵌套元组
val mulTuple = ("hello", 100, 'a', (0.3, "scala"), true)
println(mulTuple._4._2)
}
}
七、集合常用函数
1. 基本属性和操作
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
//(1)获取集合长度
println(list.length) // Set 和 Map 没有 length
//(2)获取集合大小,等同于 length
println(list.size)
//(3)循环遍历
list.foreach(println)
//(4)迭代器
for (elem <- list.iterator) {
println(elem)
}
//(5)生成字符串
println(list.mkString(","))
//(6)是否包含
println(list.contains(3))
}
}
2. 衍生集合
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
val list2: List[Int] = List(11, 2, 3, 44, 5, 66, 77, 88)
//(1)获取集合的头
val res1: Int = list1.head
println(res1)
//(2)获取集合的尾(去除头元素后的集合)
val res2: List[Int] = list1.tail
println(res2)
//(3)集合最后一个数据
val res3: Int = list1.last
println(res3)
//(4)集合初始数据(不包含最后一个)
val res4: List[Int] = list1.init
println(res4)
//(5)反转
val res5: List[Int] = list1.reverse
println(res5)
//(6)取前(后)n 个元素
val res6: List[Int] = list1.take(3) // 取前 3 个
println(res6)
val res7: List[Int] = list1.takeRight(3) // 取后 3 个
println(res7)
//(7)去掉前(后)n 个元素
val res8: List[Int] = list1.drop(3) // 去掉前 3 个
println(res8)
val res9: List[Int] = list1.dropRight(3) // 去掉后 3 个
println(res9)
//(8)并集(合并集合),Set 合并会去重,Map 合并会添加覆盖
val union: List[Int] = list1.union(list2)
println(union)
println(list1 ::: list2)
//(9)交集
val intersection: List[Int] = list1.intersect(list2)
println(intersection) // 两个集合的公共元素
//(10)差集
val diff1: List[Int] = list1.diff(list2) // 属于 list1 且不属于 list2 的元素
println(diff1)
val diff2: List[Int] = list2.diff(list1) // 属于 list2 且不属于 list1 的元素
println(diff2)
//(11)拉链(两个集合同位置的元素构成一个二元组形成的集合,落单部分丢弃)
val zip1: List[(Int, Int)] = list1.zip(list2) // 元组中 list1 元素在前
println(zip1)
val zip2: List[(Int, Int)] = list2.zip(list1)
println(zip2)
//(12)滑窗(滑动开窗)
val slide1: Iterator = list1.sliding(3) // 开窗大小为 3 个元素,每次滑动 1 个元素
for(elem <- slide) {
println(elem) // elem: List[Int]
}
// 滚动窗口
val slide2: Iterator = list2.sliding(3, 3) // 开窗大小为3个元素,每次滑动3个元素
}
}
3. 集合计算初级函数
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val list1: List[Int] = List(1, 5, -3, 4, 2, -7)
val list2 = List(("a", 1), ("b", 5), ("c", -3), ("d", 4), ("e", 2), ("f",-7))
//(1)求和
val res1: Int = list1.sum
println(res1)
// 等价于
val res2: Int = 0
for(elem <- list1) res2 += elem
println(res2)
//(2)求乘积
val res3: Int = list1.product
println(res3)
//(3)最大值
val res4: Int = list1.max
println(res4)
// maxBy 可以指定比较的元素
val res5: Int = list2.maxBy( _._2 ) //((tuple:(String,Int)) => tuple._2)
println(res5)
//(4)最小值
val res6: Int = list1.min
println(res6)
val res7: Int = list2.minBy( _._2 ) //((tuple:(String,Int)) => tuple._2)
println(res7)
//(5)排序(针对有序集合 List)
// 5.1 使用 sorted
val res8: List[Int] = list1.sorted // 默认升序,list1.sorted(Ordering[Int])
println(res8)
val res9 = list1.sorted(Ordering[Int].reverse) // 使用隐式参数指定降序
println(res9)
// 5.2 使用 sortBy 指定排序元素
val ress = list2.sortBy(_) //元组排序,先比较第一个元素,相同则比较第二个元素,依次类推
println(ress)
val res10 = list2.sortBy(_._2) // 默认升序,list2.sortBy(_._2)(Ordering[Int])
println(res10)
val res11 = list2.sortBy(_._2)(Ordering[Int].reverse) // 降序
println(res11)
// 5.3 使用 sortWith 指定排序规则,类似于 Java 的 Comparator
val res12 = list1.sortWith( _ < _ ) // 升序,((a:Int, b:Int) => a < b)
println(res12)
}
}
4. 集合计算高级函数
4.1 过滤
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4,5,6,7,8,9)
/*
过滤函数:filter(func: A => Boolean),true 保留
*/
// 选取偶数
val evenList = list.filter(_ % 2 == 0) // ((a: Int) => a % 2 == 0)
println(evenList)
}
}
4.2 转化/映射
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4,5,6,7,8,9)
/*
映射函数:map(func: A => B)
*/
// 所有元素乘以 2
val resList1 = list.map(_ * 2)
println(resList1)
}
}
4.3 扁平化
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val nestedList: List[List[Int]] = List(List(1,2,3),List(4,5),List(6,7,8,9))
/*
扁平化函数:flatten(a: List[List[A]])
*/
val flatList = nestedList.flatten
println(flatList)
}
}
4.4 扁平化 + 映射
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
// 针对一组字符串进行分词后以单词列表输出
val words: List[String] = List("Hello world", "hello scala and java", "good job", "work hard")
/*
扁平化映射函数:flatMap(func: A => B)
*/
val flatMapList = words.flatMap(_.split(" ")) // 分词并扁平化
println(flatMapList)
// 等价于
val splitWord: List[Array[String]] = words.map(_.split(" "))
val flattenList = splitWord.flatten
println(flattenList)
}
}
4.5 分组
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4,5,6,7,8,9)
/*
分组函数:groupBy(func: A => K),返回值为 Map[K, List[A]]
*/
// 按奇偶分组
val groupMap1: Map[String, List[Int]] = list.groupBy(x => {
if(x % 2 == 0) "偶数" else "奇数"
})
println(groupMap1)
// 给定一组词汇,按单词的首字母分组
val wordList: List[String] = List("alice", "bob", "canon", "curry", "bike")
val groupMap2: Map[Char, List[String]] = wordList.groupBy( _.charAt(0) )
}
}
4.6 简化(归约)
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
/*
归约函数:
reduce(op: (A1, A1) => A1): A1,底层是调用 reduceLeft()
reduceLeft(op: (B, A) => B): B,聚合状态 B 可以和当前数据 A 类型不一致
reduceRight(op: (A, B) => B): B,聚合状态 B 在右
*/
// 计算累加
val res1: Int = list.reduce(_ + _) // (((1+2)+3)+4) = 10
val res2: Int = list.reduceLeft(_ + _) // (((1+2)+3)+4) = 10
val res3: Int = list.reduceRight(_ + _) // 1+(2+(3+4)) = 10
// 计算累减
val res4: Int = list.reduce(_ - _) // (((1-2)-3)-4) = -8
val res5: Int = list.reduceLeft(_ - _) // (((1-2)-3)-4) = -8
val res6: Int = list.reduceRight(_ - _) // 1-(2-(3-4)) = -2
}
}
4.7 折叠
object TestCollectionFunc {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
/*
折叠函数:
fold(z: A1)(op: (A1, A1) => A1): A1,底层调用foldLeft,z 是初始状态值
foldLeft(z: B)(op: (B, A) => B): B
foldRight(z: B)(op: (A, B) => B): B,底层调用 reverse.foldLeft
*/
val result1: Int = list.fold(10)(_ + _) // 10 + 1 + 2 + 3 + 4 = 20
val result2: Int = list.foldLeft(10)(_ - _) // 10 - 1 - 2 - 3 - 4 = 0
val result3: Int = list.foldRight(11)(_ - _) // 1 - (2 - (3 - (4 - 11))) = 9
}
}
4.8 应用案例
object TestMergeMap {
def main(args: Array[String]): Unit = {
// 合并 map:没有 key 则添加,有 key 则值相加
val map1 = Map("a" -> 1, "b" -> 2, "c" -> 3)
val map2 = mutable.Map("a" -> 4, "b" -> 5, "c" -> 6, "d" -> 8)
val mergeMap = map1.foldLeft(map2)( (b: mutable.Map[String, Int], a: (String, Int)) => {
val key = a._1
val value = a._2
b(key) = b.getOrElse(key, 0) + value
b
})
}
}
5. WordCount 案例
5.1 案例 1
单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果
object TestWordCount {
def main(args: Array[String]): Unit = {
// 原始字符串集合
val strs: List[String] = List("Hello Scala Hbase Kafka", "Hello Scala Hbase", "Hello Scala", "Hello")
// 分词并扁平化
val words: List[String] = strs.flatMap(_.split(" "))
// 分组
val groupWords: Map[String, List[String]] = words.groupBy(w=>w) // 不能使用 _
// 计数
// (String, List) => (String, Int)
val countMap: Map[String, Int] = groupWords.map(kv => (kv._1, kv._2.length))
// 将 map 转化为 list 再降序取前 3
val resultList: List[(String, Int)] = countMap.toList.sortWith(_._2 > _._2)
.take(3)
println(resultList)
}
}
5.2 案例 2
针对已经进行预统计的字符串集合,将集合中出现的相同的单词,进行计数,取计数排名前三的结果
object TestFlexWordCount {
def main(args: Array[String]): Unit = {
// 原始字符串集合
val strs: List[(String, Int)] = List(
("Hello Scala Hbase Kafka", 2),
("Hello Scala Hbase", 1),
("Hello Scala", 3),
("Hello", 4)
)
// 分词
val wordList: List[(String, Int)] = strs.flatMap(elem => { // 一进多出需扁平化
for(a <- elem._1.split(" ")) yield (a, elem._2)
})
// 合并计数
import scala.collection.mutable
var countMap: mutable.Map[String, Int] = mutable.Map()
countMap = wordList.foldLeft(countMap)( (countMap, elem) => {
val key = elem._1
val value = elem._2
countMap(key) = countMap.getOrElse(key, 0) + value
countMap
})
// 将 Map 转化为 List 并降序取前 3
val resultList: List[(String, Int)] = countMap.toList.sortWith(_._2 > _._2)
.take(3)
println(resultList)
}
}
八、队列
队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和 dequeue
object TestQueue {
def main(args: Array[String]): Unit = {
// 创建可变队列
import scala.collection.mutable
val queue1 = new mutable.Queue[String]()
val queue2 = mutable.Queue() // 伴生对象 apply 方法
// 入队
queue1.enqueue("a", "b", "c")
println(queue1)
// 出队
println(queue1.dequeue())
println(queue1)
println(queue1.dequeue())
println(queue1)
println(queue1.dequeue())
println(queue1)
// 创建不可变队列
import scala.collection.immutable
// val queue = new immutable.Queue() // 密封类不能使用 new 创建
val queue3 = Queue("a", "b", "c") // 伴生对象 apply 方法
println(queue3)
// 不可变队列的入队和出队操作会创建新的队列,自身不改变
val queue4 = queue3.enqueue("d")
println(queue3)
println(queue4)
}
}
九、并行集合
Scala 为了充分使用多核 CPU,提供了并行集合,用于多核环境的并行计算
object TestParallel {
def main(args: Array[String]): Unit = {
// 串行集合
val result1: immutable.IndexedSeq[Long] = (1 to 100).map( a => {
Thread.currentThread.getId
})
println(result1) // 都是一个线程,Vector
// 并行集合
val result2: ParSeq[Long] = (1 to 100).par.map( a => {
Thread.currentThread.getId
})
println(result2) // 有多个线程处理,ParVector
}
}