当前位置: 首页 > article >正文

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

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.kler.cn/a/400841.html

相关文章:

  • Java 使用MyBatis-Plus数据操作关键字冲突报错You have an error in your SQL syntax问题
  • 【2】猫眼娱乐后端开发面试题整理
  • ChatGPT学术专用版,一键润色纠错+中英互译+批量翻译PDF
  • Android 使用Retrofit 以纯二进制文件流上传文件
  • PHP 表单 - 必需字段
  • 亿咖通科技应邀出席微软汽车行业智享会,分享ECARX AutoGPT全新实践
  • 力扣经典面试13罗马数字转整数
  • springboot006基于SpringBoot的网上订餐系统(源码+包运行+LW+技术指导)
  • DOM NodeList 对象简介
  • 7天掌握SQL - 第一天:数据库基础与SQL入门
  • 在AndroidStudio中新建项目时遇到的Gradle下载慢问题,配置错的按我的来,镜像地址不知道哪个网页找的,最主要下载要快
  • 汽车资讯新趋势:Spring Boot技术解读
  • ClickHouse的介绍、安装、数据类型
  • 泷羽sec-安全见闻(8)
  • Gradio 和 Streamlit 安装与使用教程
  • 在Unity中使用Epplus写Excel
  • 使用Mybatis向Mysql中的插入Point类型的数据全方位解析
  • API 数据处理与 SQL 批量更新技巧:CASE 语句优化操作指南
  • RadSystems 自定义页面全攻略:个性化任务管理系统的实战设计
  • CSS3_过渡(八)
  • 力扣(leetcode)面试经典150题——26. 删除有序数组中的重复项
  • 35.搜索插入位置-力扣(LeetCode)
  • ssm139选课排课系统的设计与开发+vue(论文+源码)_kaic
  • React Native 全栈开发实战班 - 打包发布之热更新
  • shell编程规范和脚本变量
  • UE5 猎户座漂浮小岛 07 场景