大数据学习15之Scala集合与泛型

news/2024/11/17 2:03:02/

1. 概述

        大部分编程语言都提供了数据结构对应的编程库,并称之为集合库(Collection Library),Scala 也不例外,且它还拥有以下优点:
易用:灵活组合运用集合库提供的方法,可以解决大部分集合问题
简洁:拜类型推断和函数式编程所赐,帮助程序员写出更简洁,更优雅的代码
安全:绝大部分错误都可以在编译期被发现
快速:集合类型的方法在实现时,都进行了调优,用户可以根据需求选择合适的集合
统一:Scala 的集合有非常严谨的继承体系,相似类型的集合拥有同样的一组方法,当然也有属于自己独有的方法。

2. 分类

        不可变集合:集合内的元素、长度一旦初始化完成就不可再进行更改,任何对集合的改变都将生成一个新的集合。不可变集合都在 scala.collection.immutable 这个包下,使用时无需手动导包。

        可变集合    :指的是这个集合本身可以动态改变,且可变集合提供了改变集合内元素的方法。可变集合都在scala.collection.mutable 这个包下,使用时需要手动导包。

3. 继承树

        

4. 上层接口

4.1. Traversable

4.1.1. 概述

        Traversable 是一个特质(trait),它是其他集合的父特质,它的子特质 immutable.Traversable 和 mutable.Traversable 分别是不可变集可变集合的父特质,集合中大部分通用的方法都是在这个特质中定义的。因此了解它的功能对学习其他集合类十分重要。

4.1.2转置集合

了解过线性代数的同学都知道,矩阵有一个转置的操作,在 Scala 中,可以轻松通过 transpose() 方法实现类似的效果。矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引,如下图:

4.1.3. 拼接集合

        新集合=集合1++集合2 

        会创建临时集合,不推荐

        新集合=Traversable.concat(集合1, 集合2, 集合3)

        预先计算所需集合大小,生成一个集合,减少临时集合的生成。

4.1.4. 计算阶乘*

        

4.1.5. 获取元素*

4.1.6. 判断元素*

4.1.7. 聚合操作

4.1.8. 类型转换

        有时候,需要把 Traversable 集合转换成其他的集合来进行操作,例如转为 Set 集快速去重,此时就需要用到toXxx() 方法(toList, toSet, toArray, toSeq 等)。

4.1.9. 填充元素

        

4.2. Iterable

4.2.1. 概述

        Iterable 代表一个可以迭代的集合,它继承了 Traversable 特质,同时也是其他集合的父特质。最重要的是,它定义了获取迭代器 iterator 的方法: def iterator: Iterator[A] ,这是一个抽象方法,它的实现类需要实现这个方法,从而实现迭代集合并返回集合中的元素。

4.2.2. 分类

        iterator()

        foreach()

4.2.3. 遍历集合

    list.foreach(println);it=list.toIterator();while(it.hasNext()){println(it.next())
}

4.2.4. 分组遍历

object IterableGroupedDemo {
def main(args: Array[String]): Unit = {
// 定义一个 Iterable 集合,存储 1~13 之间的所有整数
val iterable = (1 to 13).toIterable
// 通过 grouped() 方法,对 Iterator 集合按照 5 个元素为一组的形式进行分组,遍历并打印结果
val iterator = iterable.grouped(5)
while (iterator.hasNext) {
println(iterator.next())
}
}

4.2.5. 按索引生成元组

/**
* 按索引生成元组
*/
object IterableGenerateTupleDemo {
def main(args: Array[String]): Unit = {
// 定义一个 Iterable 集合,存储"A", "B", "C", "D", "E"
val i = Iterable("A", "B", "C", "D", "E")
// 通过 zipWithIndex() 方法按照`字符串 -> 索引`生成新的集合
val result1 = i.zipWithIndex
println(s"result1 = ${result1}")
// 通过 map() 方法按照`索引 -> 字符串`生成新的集合
val result2 = result1.map(x => x._2 -> x._1)
println(s"result2} = ${result2}")
}
}

4.2.6. 判断集合是否相同

        通过 sameElements() 方法来实现该需求。

4.3. Seq

4.3.1. 概述

        Seq(Sequence)特质代表按照一定顺序排列的元素序列,序列是一种特别的可迭代集合,它的元素特点是有序(元素存取顺序一致),可重复,有索引。

4.3.2. 分类

        

4.3.3. 获取元素与长度

object SeqGetElementAndLenDemo {
def main(args: Array[String]): Unit = {
// 创建 Seq 集合,存储元素 1, 2, 3, 4, 5
val s = (1 to 5).toSeq
// 打印集合元素
s.foreach(x => println(x))
// 简化版
s.foreach(println(_))
s.foreach(println)
// 打印集合长度
println(s.size)
// 获取索引为 2 的元素
// 通过集合名(索引)的方式获取
println(s(2))
// 通过集合伴生对象的 apply 方法获取
println(s.apply(2))
}
}

4.3.4. 获取元素索引*

4.3.5. 判断集合是否包含指定元素

4.3.6. 修改元素

        

        

4.4. Set

去重;

HashSet 唯一无序;

ListSet 唯一有序(添加顺序);

TreeSet 唯一有序(自然顺序);

4.5. Map

HashMap:元素特点 Key 唯一、无序。
ListMap:元素特点 Key 唯一、有序(元素添加的顺序)。
TreeMap:元素特点 Key 唯一、排序(按自然顺序排序)。

5. 下层实现

  敲代码练习

数组 Array

元组 Tuple

列表 List

集 Set

映射 Map

迭代器 Iterator

栈 Stack

队列 Queue

6. 函数式编程

        函数式编程将计算视为数学函数的求值,强调纯函数、不可变性和高阶函数的使用。函数式编程的核心思想是将计算任务分解为函数之间的组合,以解决问题和构建软件。

内容另起;

泛型 Generics

1. 分类

1.1. 泛型集合

        

// 定义集合不指定泛型,可以随意存储sca
val list1 = List(2, 3.14, "abc", true, null)
// 定义集合指定泛型,只能存储指定类型数据
val list2 = List[Int](1, 2, 3, 4, 5)

1.2. 泛型方法

def 方法名[泛型名称](...): Unit {
}

1.3. 泛型类

/**
* 泛型类
*/
object GenericsClassDemo {
// 定义一个 Pair 泛型类,该类包含两个字段,且两个字段的类型不固定
class Pair[T](var a: T, var b: T)
case class Person(name: String, age: Int)
def main(args: Array[String]): Unit = {
// 创建不同类型的 Pair 泛型类对象,并打印
val pair1 = new Pair[Int](10, 20)
println(pair1.a, pair1.b)
val pair2 = new Pair[Person](Person("张三", 18), Person("李四", 19))
println(pair2.a, pair2.b)
}
}

1.4. 泛型特质

/**
* 泛型特质
*/
object GenericsTraitDemo {
// 定义泛型特质 Logger,该特质有一个变量 name 和 log 方法,它们都使用 Logger 特质的泛型
trait Logger[T] {
val name: T
def log(b: T)
}
// 定义单例对象 InfoLogger 继承 Logger 特质
object InfoLogger extends Logger[String] {
override val name: String = "INFO"
override def log(b: String): Unit = println(b)
}
def main(args: Array[String]): Unit = {
InfoLogger.log(s"${InfoLogger.name}:这是一条日志信息")
}
}

2. 上下界

2.1. 上界

        使用 T <: 类型 表示给类型添加一个上界,表示泛型参数必须是继承自该类型或是其类型本身。
        例如: [T <: Animal] 表示泛型 T 的数据类型必须是 Animal 类型或者 Animal 的子类型。

/**
* 上界
*/
object GenericsUpDemo {
// 定义一个 Animal 类
class Animal
// 定义一个 Cat 类,继承 Animal 类
class Cat extends Animal
// 定义一个 Tom 类,继承 Cat 类
class Tom extends Cat
// 定义一个泛型方法 demo,该方法接收一个 Array 参数
// 限定 demo 方法的 Array 元素类型只能是 Animal 或者 Animal 的子类型
def demo[T <: Cat](arr: Array[T]): Unit = {
println(arr.mkString("Array(", ", ", ")"))
}
def main(args: Array[String]): Unit = {
// 测试调用 demo 方法,传入不同元素类型的 Array
// 定义上界以后,下面这行代码会报错
//demo(Array(new Animal, new Animal))
demo(Array(new Cat, new Cat))
demo(Array(new Tom, new Tom))
}
}

2.2. 下界

        使用 T >: 类型 表示给类型添加一个下界,表示泛型参数必须是该类型的祖先类或是其类型本身。
        例如: [T >: Person] 表示泛型 T 的数据类型必须是 Person 类型或者 Person 的祖先类型。

/**
* 下界
*/
object GenericsDownDemo {
// 定义一个 Animal 类
class Animal
// 定义一个 Cat 类,继承 Animal 类
class Cat extends Animal
// 定义一个 Tom 类,继承 Cat 类
class Tom extends Cat
// 定义一个 demo 泛型方法,该方法接收一个 Array 参数
// 限定 demo 方法的 Array 元素类型只能是 Person 或者 Hero
def demo[T >: Cat](arr: Array[T]): Unit = {
println(arr.mkString("Array(", ", ", ")"))
}
def main(args: Array[String]): Unit = {
// 测试调用 demo 方法,传入不同元素类型的 Array
demo(Array(new Animal, new Animal))
demo(Array(new Cat, new Cat))
// 定义下界以后,下面这行代码会报错
//demo(Array(new Tom, new Tom))
}
}

3. 非变、协变、逆变

Spark 源代码中大量使用了协变、逆变、非变,学习该知识点对将来阅读 Spark 源码很有帮助。
非变:A 类和 B 类之间存在父子关系,泛型非变操作后两个泛型类之间不会产生任何关系。
协变:A 类和 B 类之间存在父子关系,泛型协变操作后两个泛型类之间也属于父子关系。
逆变:A 类和 B 类之间存在父子关系,泛型逆变操作后两个泛型类之间关系进行颠倒。

3.1. 语法格式

非变: Temp[T]{} 。泛型默认即是非变的。
协变: Temp[+T]{} 。
逆变: Temp[-T]{} 。

/**
* 非变、协变、逆变
*/
object GenericsVariantDemo {
class A
class B extends A
// 非变
class Temp1[T]
// 协变
class Temp2[+T]
// 逆变
class Temp3[-T]
def main(args: Array[String]): Unit = {
// 测试非变
val t1: Temp1[B] = new Temp1[B]
// 编译报错,非变操作后两个类之间不会产生任何关系
//val t2: Temp1[A] = t1
// 测试协变
val t3: Temp2[B] = new Temp2[B]
// 正常编译且运行,协变操作后两个类之间关系不发生任何改变
val t4: Temp2[A] = t3
// 测试逆变
val t5: Temp3[B] = new Temp3[B]
// 编译报错,逆变操作后两个类之间关系进行颠倒
//val t6: Temp3[A] = t5
// 以下逆变操作正常编译且运行
val t7: Temp3[A] = new Temp3[A]
val t8: Temp3[B] = t7
}
}


http://www.ppmy.cn/news/1547590.html

相关文章

力扣第 54 题 **螺旋矩阵**

力扣第 54 题是 螺旋矩阵&#xff08;Spiral Matrix&#xff09;。题目要求按螺旋顺序遍历一个 m x n 的矩阵&#xff0c;并返回遍历的结果。 解题思路 螺旋矩阵的遍历顺序是 从左到右&#xff0c;然后 从上到下&#xff0c;接着 从右到左&#xff0c;最后 从下到上&#xff…

AWS CLI

一、介绍 1、简介 aws configure 是 AWS 提供的一个命令行工具&#xff0c;用于快速配置 AWS CLI&#xff08;命令行界面&#xff09;和 AWS SDK&#xff08;软件开发工具包&#xff09;中使用的凭证、默认区域以及输出格式。这个命令是 AWS CLI 中的一个配置工具&#xff0c…

Mac解压包安装MongoDB8并设置launchd自启动

记录一下在mac上安装mongodb8过程&#xff0c;本机是M3芯片所以下载m芯片的安装包&#xff0c;intel芯片的类似操作。 首先下载安装程序包。 # M芯片下载地址 https://fastdl.mongodb.org/osx/mongodb-macos-arm64-8.0.3.tgz # intel芯片下载地址 https://fastdl.mongodb.org…

子网划分学习

举例 10.0.1.0/30&#xff0c;这个给的就是网络地址&#xff0c;那么意思就是网络地址就是一个网段 可以得到网络地址&#xff0c;主机地址&#xff0c;广播地址 这个就是一个网段&#xff0c;但是他有多少的子网呢&#xff0c;该怎么算呢&#xff0c;首先根据子网掩码&…

Spring Boot框架在电商领域的应用

1 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。这样的大环境让那些止步不前&#…

Pytorch学习--神经网络--完整的模型验证套路

一、选取的图片 全部代码依托于该博客 二、代码&#xff08;调用训练好的模型&#xff09; import torch import torchvision from PIL import Image from model import *img_path "dog.png" image Image.open(img_path)print(image.size)transform torchvisi…

wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器

嗨&#xff0c;大家好&#xff0c;我是小华同学&#xff0c;关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 wflow-web是一个开源的工作流设计器&#xff0c;它支持可视化拖拽表单组件&#xff0c;动态任意层级结构审批节点&#xff0c;以及复杂流程条件的设置…

全面评估ASPICE标准对汽车软件开发的影响与效果

在评估ASPICE&#xff08;Automotive SPICE&#xff09;标准的效果时&#xff0c;可以从多个维度进行考量&#xff0c;以确保全面且准确地反映该标准对汽车软件和嵌入式系统开发过程的积极影响。以下是一些关键的评估方面&#xff1a; 1. 过程改进与标准化 标准化程度&#xf…