详解 Scala 的集合类型

一、集合简介

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
        
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/646242.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于docxtpl的模板生成Word

docxtpl是一个用于生成Microsoft Word文档的模板引擎库。它结合了docx模块和Jinja2模板引擎&#xff0c;使用户能够使用Microsoft Word模板文件并在其中填充动态数据。这个库提供了一种方便的方式来生成个性化的Word文档&#xff0c;并支持条件语句、循环语句和变量等控制结构&…

Spring Boot集成testcontainers快速入门Demo

1.什么是testcontainers&#xff1f; Testcontainers 是一个用于创建临时 Docker 容器进行单元测试的 Java 库。当我们想要避免使用实际服务器进行测试时&#xff0c;它非常有用。&#xff0c;官网介绍称支持50多种组件。​ 应用场景 数据访问层集成测试&#xff1a; 使用My…

HTTP交互导致ECONNABORTED的原因之一

背景&#xff1a; 本次记录的&#xff0c;是一次使用HTTP交互过程中遇到的问题&#xff0c;问题不大&#xff0c;就是给题目上这个报错补充一种可能的解决方案。 程序大致流程&#xff1a; 1. 设备向服务器A请求信息 2. 拿到回复记录下回复内容中的数据包下载地址等信息 3…

2024GDCPC广东省赛记录

比赛流程体验&#xff0c;依托&#xff0c;开赛几分钟了&#xff0c;选手还卡在门外无法入场&#xff0c;也没给延时&#xff0c;说好的桌上会发三支笔&#xff0c;于是我们就没准备&#xff0c;要了三次笔&#xff0c;终于在一小时后拿到了&#x1f605; 比赛题目体验&#xf…

PyTorch深度学习快速入门——P1-P13

环境配置 Anaconda&#xff0c;创建conda create -n pytorch python3.12&#xff0c;使用conda activate pytorch切换到环境。安装pytorch&#xff0c;conda install pytorch torchvision torchaudio pytorch-cuda11.8 -c pytorch -c nvidia&#xff0c;使用import torch&…

力扣496. 下一个更大元素 I

Problem: 496. 下一个更大元素 I 文章目录 题目描述思路复杂度Code 题目描述 思路 因为题目说nums1是nums2的子集&#xff0c;那么我们先把nums2中每个元素的下一个更大元素算出来存到一个映射里&#xff0c;然后再让nums1中的元素去查表即可 复杂度 时间复杂度: O ( n 1 n 2…

宁夏银川、山东济南、中国最厉害的改名大师的老师颜廷利教授的前沿思想观点

在当代社会&#xff0c;一个响亮的声音穿越了传统的迷雾&#xff0c;它来自东方哲学的殿堂&#xff0c;由一位现代学者颜廷利教授所发出。他的话语&#xff0c;如同一股清泉&#xff0c;在混沌的世界里激荡着思考的波澜&#xff1a;"有‘智’不在年高&#xff0c;无‘智’…

福昕PDF编辑器自定义快捷方式

你是否为用不惯福昕PDF编辑器自带的快捷键而发愁&#xff1f;今天&#xff0c;我和大家分享一下如何设置自己想要的快捷键方式&#xff0c;希望能对大家有帮助。 步骤一&#xff1a;打开福昕PDF编辑&#xff0c;并找到更多命令 步骤二&#xff1a;切换到键盘一栏&#xff0c;并…

Stream流常用操作

一、中间操作 中间操作是返回一个新的流&#xff0c;并在返回的流中包含所有之前的操作结果。它们总是延迟计算&#xff0c;这意味着它们只会在终止操作时执行&#xff0c;这样可以最大限度地优化资源使用。 1. filter(过滤) filter()方法接受一个谓词&#xff08;一个返回boo…

栈和队列的基本见解

1.栈 1.1栈的基本概念和结构&#xff1a; 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出的原则。 压栈&#xff1a;栈的插入操作叫做进栈/压栈…

【java程序设计期末复习】chapter2 基本数据类型与数组

基本数据类型与数组 一&#xff0c;标识符和关键字 标识符 定义 用来标识类名、变量名、方法名、类型名、数组名、文件名的有效字符序列称为标识符&#xff0c;简单地说&#xff0c;标识符就是一个名字 。 性质 &#xff08;1&#xff09;标识符由字母、下划线、美元符号和…

cocos creator做圆形进度条

效果图&#xff1a; 我们在开发过程中经常要用到圆形进度条&#xff0c;例如技能CD 原文链接 之前写了一篇cocos2dx-lua_ProgressTimer创建扇形进度条,这里简单记录下在cocosCreator中如何制作。 具体方法 cocosCreator做起来比2dx还是要简单很多&#xff0c;首先给节点添加p…

PageHelper分页

文章目录 PageHelper分页ThreadLocalMap和ThreadLocal执行完PageHelper.startPage之后&#xff0c;分页参数存储到哪里了&#xff1f;Page和List的关系&#xff1f;PageInterceptor分页拦截器的作用&#xff1f;PageInfo的作用与结构&#xff1f;最后看下引入的pagehelper分页依…

Linux-部分:实用指令

1 指定运行级别 1&#xff09;基本介绍&#xff1a; 运行级别说明&#xff1a; 0&#xff1a;关机1&#xff1a;单用户【找回丢失密码】2&#xff1a;多用户状态没有网络服务3&#xff1a;多用户状态有网络服务4&#xff1a;系统未使用保留给用户5&#xff1a;图形界面6&…

新业务 新市场 | 灵途科技新品亮相马来西亚亚洲防务展

5月6日&#xff0c;灵途科技携新品模组与武汉长盈通光电&#xff08;股票代码&#xff1a;688143&#xff09;携手参加第18届马来西亚亚洲防务展。首次亮相海外&#xff0c;灵途科技便收获全球客户的广泛关注&#xff0c;为公司海外市场开拓打下坚实基础。 灵途科技与长盈通共同…

基于Llama 3搭建中文版(Llama3-Chinese-Chat)大模型对话聊天机器人

前面两篇博文&#xff0c;我们分别在个人笔记本电脑部署了Llama 3 8B参数大模型&#xff0c;并使用Ollama搭建了基于 Web 可视化对话聊天机器人&#xff0c;可以在自己电脑上愉快的与Llama大模型 Web 机器人对话聊天了。但在使用过程中&#xff0c;笔者发现Llama大模型经常出现…

避免锁表:为Update语句中的Where条件添加索引字段

最近在灰度环境中遇到一个问题&#xff1a;某项业务在创建数据时耗时异常长&#xff0c;但同样的代码在预发环境中并未出现此问题。起初我们以为是调用第三方接口导致的性能问题&#xff0c;但通过日志分析发现第三方接口的响应时间正常。最终&#xff0c;我们发现工单表的数据…

【C++】C++11(一)

C11是一次里程碑式的更新&#xff0c;我们一起来看一看~ 目录 列表初始化&#xff1a;{ }初始化&#xff1a;std::initializer_list&#xff1a; 声明&#xff1a;auto&#xff1a;decltype&#xff1a; STL的一些变化&#xff1a; 列表初始化&#xff1a; { }初始化&#xf…

音视频开发4-补充 FFmpeg 开发环境搭建 -- 在windows 上重新build ffmpeg

本节的目的是在windows 上 编译 ffmpeg 源码&#xff0c;这样做的目的是&#xff1a;在工作中可以根据工作的实际内容裁剪 ffmpeg&#xff0c;或者改动 ffmpeg 的源码。 第一步 &#xff1a;下载&#xff0c; 安装&#xff0c;配置 &#xff0c;运行 msys64 下载 下载地址&…