详解 Scala 的集合类型

news2024/11/17 23:49:01

一、集合简介

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】fork和exec中的信号继承探索

fork和exec中的信号继承探索 一、结论二、代码验证2.1 代码编写2.2 代码执行 三、linux源码验证四、APUE中的验证五、其他 一、结论 fork时子进程会继承父进程的信号处理方式&#xff0c;包括父进程设置信号为SIG_DFL或SIG_IGN或捕获后设置自定义处理函数。exce时子进程会继承…

有些错误,常犯常新、常新常犯:记录一个使用element-plus的tooltip组件的错误

使用element-plus的tooltip组件&#xff0c;最开始的写法是这样的&#xff1a; <el-tooltipclass"box-item"effect"dark"content"tooltip content" ><el-button v-if"isDisabled" :underline"false" type"pr…

一文扫尽Nas常用Docker软件

NAS&#xff08;Network Attached Storage&#xff0c;网络附加存储&#xff09;设备上的Docker软件选择取决于您的具体需求和用途。以下是一些NAS上常用的Docker软件推荐&#xff1a; Docker管理工具&#xff1a; Watchtower&#xff1a;它可以自动更新Docker容器中的镜像&…

从零开始学Vue3--环境搭建

1.搭建环境 下载nodejs nodejs下载地址 更新npm npm install -g npm 设置npm源&#xff0c;加快下载速度 npm config set registry https://registry.npmmirror.com 使用脚手架创建项目 npm create vuelatest 根据你的需要选择对应选项 进入新建的项目下载依赖 npm in…

kaggle竞赛实战3

接前文&#xff0c;本文主要做以下几件事&#xff1a; 1、把前面处理完的几个表拼成一个大表 2、做特征衍生&#xff08;把离散特征和连续特征两两组合得出&#xff09; # In[89]: #开始拼接表 transaction pd.concat([new_transaction, history_transaction], axis0, ignor…

STM32 USART的字符编码(发送器的实现逻辑)

目录 概述 1 字符编码 1.1 USART 字符说明 1.2 字长编程 2 发送器 2.1 字符发送 2.2 可配置的停止位 2.3 配置停止位方法 3 单字节通信 4 中断字符 5 空闲字符 概述 本文主要讲述STM32 USART的发送端功能实现的原理&#xff0c;包括字节编码长度&#xff0c;发送器…

Cyber Weekly #8

赛博新闻 1、微软召开年度发布会Microsoft Build 2024 本周&#xff08;5.22&#xff09;微软召开了年度发布会&#xff0c;Microsoft Build 2024&#xff0c;发布了包括大杀器 Copilot Studio 在内的 50 项更新。主要包括&#xff1a; 硬件层面&#xff1a;与英伟达 & A…

网络空间安全数学基础·群

重点&#xff1a; 1. 群及子群的定义及相关结论 2. 群的判断,子群的判断 3. 群的阶,元素的阶,它们的相互关系 4. 同态,同构,核子群 2.1群的定义 定义&#xff1a;设G是一非空集合。如果在G上定义了一个代数运算&#xff0c;称为乘法&#xff0c;记为ab&#xff0c;而且这个运…

【STL】C++ vector基本使用

目录 一 vector常见构造 1 空容器构造函数&#xff08;默认构造函数&#xff09; 2 Fill 构造函数 3 Range 构造函数 4 拷贝构造函数 5 C11构造 二 vector迭代器 1 begin && end 2 rbegin && rend 3 补充排序 三 vector 容量操作 1 size 2 resize …

进程信号(1)

目录 一、信号 1.1、生活中的信号 1.2、Linux中的信号 二、信号处理常见方式 三、信号的产生 3.1、简单理解信号的保存和发送 3.2、键盘产生信号 3.3、核心转储 3.4、系统调用接口产生信号 3.4.1、kill 3.4.2、raise 3.4.3、abort 3.5、软件条件产生信号 3.6、硬…

【操作系统】发展与分类(手工操作、批处理、分时操作、实时操作)

2.操作系统发展与分类 思维导图 手工操作阶段&#xff08;此阶段无操作系统&#xff09; 需要人工干预 缺点&#xff1a; 1.用户独占全机&#xff0c;资源利用率低&#xff1b; 2.CPU等待手工操作&#xff0c;CPU利用不充分。 批处理阶段&#xff08;操作系统开始出现&#x…

firewalld 防火墙

firewalld概述 Linux系统防火墙从CentOS7开始的默认防火墙工作在网络层&#xff0c;属于包过滤防火墙 Firewalld和iptables的关系 netfilter 位于Linux内核中的包过滤功能体系称为Linux防火墙的“内核态” firewalld Centos默认的管理防火墙规则的工具称为防火墙的“用…

【C++】右值引用 移动语义

目录 前言一、右值引用与移动语义1.1 左值引用和右值引用1.2 右值引用使用场景和意义1.3 右值引用引用左值及其一些更深入的使用场景分析1.3.1 完美转发 二、新的类功能三、可变参数模板 前言 本篇文章我们继续来聊聊C11新增的一些语法——右值引用&#xff0c;我们在之前就已…

sqli-lib4-6关教程

SERIES-4 输入?id1 输入?id2-1&#xff0c;说明该数据类型为字符型 输入?id1’ 输入?id1"&#xff0c;说明闭合符号为" 输入?id1")– 输入?id1") order by 3– 输入?id1") order by 4– 数据共三列&#xff0c;输入?id-1") union selec…

InfLLM的笔记

文件中提供的代码是一个Python函数chat_loop&#xff0c;它是聊天系统的核心循环。以下是对这段代码逻辑的梳理&#xff1a; 函数定义与参数 chat_loop函数接收多个参数&#xff0c;用于配置聊天模型和聊天环境。参数包括模型路径、设备类型、GPU数量、最大GPU内存、数据类型…

K8s的kubectl的基本操作

K8s的kubectl的基本操作 K8s基本信息的查看 查看版本信息 kubectl versio查看资源对象简写 kubectl api-resources查看集群信息 kubectl cluster-info配置kubectl自动补全 source <(kubectl completion bash)查看master节点状态 kubectl get cs查看命名空间 kubectl…

Elastic Cloud 将 Elasticsearch 向量数据库优化配置文件添加到 Microsoft Azure

作者&#xff1a;来自 Elastic Serena Chou, Jeff Vestal, Yuvraj Gupta 今天&#xff0c;我们很高兴地宣布&#xff0c;我们的 Elastic Cloud Vector Search 优化硬件配置文件现已可供 Elastic Cloud on Microsoft Azure 用户使用。 此硬件配置文件针对使用 Elasticsearch 作…

<el-table>根据后端返回数据决定合并单元格的数量(521特别版)

文章目录 一、需求说明二、用到的方法三、代码&#xff08;只展示了本文章重点代码&#xff09; 一、需求说明 &#x1f49d;仅合并第一列&#xff0c;其余为固定列 二、用到的方法 &#x1f48c;合并单元格可以采用三种方法 &#x1f495;1. 手写表格 简单 但没有饿了么写…

力扣HOT100 - 136. 只出现一次的数字

解题思路&#xff1a; class Solution {public int singleNumber(int[] nums) {int single 0;for (int num : nums) {single ^ num;}return single;} }

生命在于学习——Python人工智能原理(1.1)

说明&#xff1a;今年学一部分人工智能方向的知识&#xff0c;网安也会穿插&#xff0c;看后续如何将二者结合起来。 一、人工智能的基本知识 1、人工智能的起源 1956年美国达特茅斯学院召开了一个夏季论班&#xff0c;首次提出人工智能的概念。 1950年图灵提出了图灵测试&a…