Kotlin 集合框架

2023-11-08

集合概述

Kotlin 标准库提供了一整套用于管理集合的工具,集合是可变数量(可能为零)的一组条目,各种集合对于解决问题都具有重要意义,并且经常用到。

集合通常包含相同类型的一些(数目也可以为零)对象。集合中的对象称为元素条目。例如,一个系的所有学生组成一个集合,可以用于计算他们的平均年龄。 以下是 Kotlin 相关的集合类型:

  • List 是一个有序集合,可通过索引(反映元素位置的整数)访问元素。元素可以在 list 中出现多次。列表的一个示例是一句话:有一组字、这些字的顺序很重要并且字可以重复。
  • Set 是唯一元素的集合。它反映了集合(set)的数学抽象:一组无重复的对象。一般来说 set 中元素的顺序并不重要。例如,字母表是字母的集合(set)。
  • Map(或者字典)是一组键值对。键是唯一的,每个键都刚好映射到一个值。值可以重复。map 对于存储对象之间的逻辑连接非常有用,例如,员工的 ID 与员工的位置。

Kotlin 让你可以独立于所存储对象的确切类型来操作集合。换句话说,将 String 添加到 String list 中的方式与添加 Int 或者用户自定义类的到相应 list 中的方式相同。 因此,Kotlin 标准库为创建、填充、管理任何类型的集合提供了泛型的(通用的,双关)接口、类与函数。

这些集合接口与相关函数位于 kotlin.collections 包中。

集合类型

Kotlin 标准库提供了基本集合类型的实现: set、list 以及 map。 一对接口代表每种集合类型:

  • 一个 只读 接口,提供访问集合元素的操作。
  • 一个 可变 接口,通过写操作扩展相应的只读接口:添加、删除和更新其元素。
val numbers = mutableListOf("one", "two", "three", "four")
numbers.add("five")   // 这是可以的
//numbers = mutableListOf("six", "seven")      // 编译错误

 更改可变集合不需要它是以 var 定义的变量:写操作修改同一个可变集合对象,因此引用不会改变。 但是,如果尝试对 val 集合重新赋值,你将收到编译错误。

集合的型变

集合层次结构

与Java对比,有什么不同

对比Java,Kotlin只是增加了"不可变"集合框架的接口,没有另起炉灶,复用Java API的所有实现类型。

提供了丰富易用的方法,例如forEach/map/flatMap。Scala也是一门JVM语言,Kotlin很多特性都参考了Scala。

运算符级别的支持,简化集合框架的访问。

Java中的类型

Kotlin的集合创建

有自己的类型,所以是"一等公民",可以赋值、传递,并在合适的条件下调用。 以下是各种函数的用法,关键点都写在注释当中了:

创建集合的最常用方法是使用标准库函数:listOf<T>()、setOf<T>()、mutableListOf<T>()、mutableSetOf<T>()​。

如果以逗号分隔的集合元素列表作为参数,编译器会自动检测元素类型。创建空集合时,须明确指定类型。

List集合的创建

// 这两个编译完成后都变成了java里面的List<T>
val intList1: List<Int> = listOf(1,2,3) //不可变
val intList2: MutableList<Int> = mutableListOf(1,2,3)  //可变

val intList4  = listOf(1,2,3)
val intList5 = mutableListOf(1,2,3)
    
// 创建空集合的时候需要指定类型
val intList6 = mutableListOf<Int>()


// 对于 List,有一个接受 List 的大小与初始化函数的构造函数,该初始化函数根据索引定义元素的值。
val doubled1 = List(3, { it * 2 })
println(doubled1) // 输出结果: [0, 2, 4]

// 如果你想操作这个集合,应使用 MutableList
val doubled2 = MutableList(3, { it * 2 })
println(doubled2) // 输出结果: [0, 2, 4]

 Map集合的创建

// "name" to "oLiver" 可以理解为K—V键值对
// Any等价于java中的Object
val map1: Map<String , Any> = mapOf("name" to "oLiver", "age" to 30)
val map2: MutableMap<String , Any> = mutableMapOf("name" to "oLiver", "age" to 30)

val map4 = mapOf("name" to "oLiver", "age" to 30)
val map5 = mutableMapOf("name" to "oLiver", "age" to 30)

// 创建空集合的时候需要指定类型
val map6 = mutableMapOf<String, Int>()

 Set集合的创建

val set1: Set<String> = setOf("one", "two", "three", "four")
val set2: MutableSet<String> = mutableSetOf("one", "two", "three", "four")

val numbersSet1 = setOf("one", "two", "three", "four")
val numbersSet2 = mutableSetOf("one", "two", "three", "four")

// 创建空集合的时候需要指定类型
val emptySet = mutableSetOf<String>()

快捷方式创建集合

// 快捷方式创建:ArrayList<T> = java.util.ArrayList<E>
// ArrayList<T> 叫做类型别名,他是指向于java相对于的工具类
// 包括HashMap,HashSet,LinkedHashMap,LinkedHashSet等都是类型别名
val stringList = ArrayList<String>()

复制集合

浅复制

要创建与现有集合具有相同元素的集合,可以使用复制操作。标准库中的集合复制操作创建了具有相同元素引用的  复制集合。 因此,对集合元素所做的更改会反映在其所有副本中。

val sourceList = mutableListOf(1, 2, 3)
val referenceList = sourceList
referenceList.add(4)
println(sourceList.joinToString())  // 输出结果:1, 2, 3, 4
println(referenceList.joinToString()) // 输出结果:1, 2, 3, 4

集合的初始化可用于限制其可变性。例如,如果构建了一个 MutableList 的 List 引用,当你试图通过此引用修改集合的时候,编译器会抛出错误。

val sourceList = mutableListOf(1, 2, 3)
val referenceList: List<Int> = sourceList
//referenceList.add(4)            // 编译错误
sourceList.add(4)
println(referenceList.joinToString()) // 显示 sourceList 当前状态, 输出结果:1, 2, 3, 4
println(sourceList.joinToString()) // 显示 sourceList 当前状态, 输出结果:1, 2, 3, 4

使用复制函数

在特定时刻通过集合复制函数,例如toList()、toMutableList()、toSet() 等等。创建了集合的快照。 结果是创建了一个具有相同元素的新集合 如果在源集合中添加或删除元素,则不会影响副本。副本也可以独立于源集合进行更改。

val sourceList = mutableListOf(1, 2, 3)
val copyList = sourceList.toMutableList()
val readOnlyCopyList = sourceList.toList()
sourceList.add(4)
println("Copy: ${copyList.joinToString()}") // Copy: 1, 2, 3
println("sourceList: ${sourceList.joinToString()}") // sourceList: 1, 2, 3, 4
println("readOnlyCopyList: ${readOnlyCopyList.joinToString()}") // readOnlyCopyList: 1, 2, 3

//readOnlyCopyList.add(4)             // 编译异常
println("Read-only copy size: ${readOnlyCopyList.size}")

这些函数还可用于将集合转换为其他类型,例如根据 List 构建 Set,反之亦然。

val sourceList = mutableListOf(1, 2, 3)
val copySet = sourceList.toMutableSet()
copySet.add(3)
copySet.add(4)
println(copySet.joinToString()) // 输出结果:1, 2, 3, 4

Kotlin的集合读写

  • 添加元素
val intList3: MutableList<Int> = mutableListOf() //不可变
for (i in 0 .. 10) {
    intList3.add(i) // 往后添加
}
println(intList3) // 输出结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
val stringList2 = ArrayList<String>()
val stringList3 = ArrayList<String>()
for (i in 0 .. 10) {
    stringList2.add("num:$i")
    stringList3 += "num:$i" // 运算符可以重载,这里 += 的用途相当于add
}
println(stringList2) // 输出结果:[num:0, num:1, num:2, num:3, num:4, num:5, num:6, num:7, num:8, num:9, num:10]
println(stringList3) // 输出结果:[num:0, num:1, num:2, num:3, num:4, num:5, num:6, num:7, num:8, num:9, num:10]
  • 删除元素
val stringList3 = ArrayList<String>()
for (i in 0 .. 10) {
    stringList3 += "num:$i" // 运算符可以重载,这里 += 的用途相当于add
}

println(stringList3) // 输出结果:[num:0, num:1, num:2, num:3, num:4, num:5, num:6, num:7, num:8, num:9, num:10]

stringList3.remove("num:2")
println(stringList3) // 输出结果是:[num:0, num:1, num:3, num:4, num:5, num:6, num:7, num:8, num:9, num:10]
stringList3 -= "num:6"
println(stringList3) // 输出结果:[num:0, num:1, num:3, num:4, num:5, num:7, num:8, num:9, num:10]
  • 访问元素,修改某个元素的值
val stringList3 = ArrayList<String>()
for (i in 0 .. 10) {
    stringList3 += "num:$i" // 运算符可以重载,这里 += 的用途相当于add
}
println(stringList3) // 输出结果:[num:0, num:1, num:2, num:3, num:4, num:5, num:6, num:7, num:8, num:9, num:10]

stringList3[0] = "HelloWorld" // 也可以根据角标来修改对应角标的值
val valueAt5 = stringList3[0]
println(valueAt5) // 输出结果:HelloWorld
println(stringList3)
  • Map集合的元素访问
val map2: MutableMap<String , Any> = mutableMapOf("name" to "oLiver", "age" to 30)
val map3 = HashMap<String, Int>()

println(map2) // 输出结果:{name=oLiver, age=30}
println(map3) // 输出结果:{}
map2["age"] = 10
map3["age"] = 10
println(map2) // 输出结果:{name=oLiver, age=10}
println(map3) // 输出结果:{age=10}
println(map3["age"]) // 输出结果:10

集合的遍历

对于遍历集合元素, Kotlin 标准库支持 迭代器 的常用机制——对象可按顺序提供对元素的访问权限,而不会暴露集合的底层结构。 当需要逐个处理集合的所有元素(例如打印值或对其进行类似更新)时,迭代器非常有用。

Iterable<T> 接口的继承者(包括 Set 与 List)可以通过调用 iterator() 函数获得迭代器。 一旦获得迭代器它就指向集合的第一个元素;调用 next() 函数将返回此元素,并将迭代器指向下一个元素(如果下一个元素存在)。 一旦迭代器通过了最后一个元素,它就不能再用于检索元素;也无法重新指向到以前的任何位置。要再次遍历集合,请创建一个新的迭代器。

val numbers = listOf("one", "two", "three", "four")
val numbersIterator = numbers.iterator()
while (numbersIterator.hasNext()) {
    println(numbersIterator.next())
}

遍历 Iterable 集合的另一种方法是众所周知的 for 循环。在集合中使用 for 循环时,将隐式获取迭代器。因此,以下代码与上面的示例等效:

val numbers = listOf("one", "two", "three", "four")
for (item in numbers) {
    println(item)
}

最后,有一个好用的 forEach() 函数,可自动迭代集合并为每个元素执行给定的代码。因此,等效的示例如下所示:

val numbers = listOf("one", "two", "three", "four")
numbers.forEach {
    println(it)
}

List 迭代器

对于列表,有一个特殊的迭代器实现: ListIterator 它支持列表双向迭代:正向与反向。 反向迭代由 hasPrevious() 和 previous() 函数实现。 此外, ListIterator 通过 nextIndex() 与 previousIndex() 函数提供有关元素索引的信息。

具有双向迭代的能力意味着 ListIterator 在到达最后一个元素后仍可以使用。

val numbers = listOf("one", "two", "three", "four")
val listIterator = numbers.listIterator()
while (listIterator.hasNext()) listIterator.next()
println("Iterating backwards:")
while (listIterator.hasPrevious()) {
    print("Index: ${listIterator.previousIndex()}")
    println(", value: ${listIterator.previous()}")
}

/**
 * Iterating backwards:
    Index: 3, value: four
    Index: 2, value: three
    Index: 1, value: two
    Index: 0, value: one
 * */

可变迭代器

为了迭代可变集合,于是有了 MutableIterator 来扩展 Iterator 使其具有元素删除函数 remove() 。因此,可以在迭代时从集合中删除元素。

val numbers = mutableListOf("one", "two", "three", "four") 
val mutableIterator = numbers.iterator()

mutableIterator.next()
mutableIterator.remove()    
println("After removal: $numbers") // After removal: [two, three, four]

除了删除元素, MutableListIterator 还可以在迭代列表时插入和替换元素。

val numbers = mutableListOf("one", "four", "four") 
val mutableListIterator = numbers.listIterator()

mutableListIterator.next()
mutableListIterator.add("two")
mutableListIterator.next()
mutableListIterator.set("three")   
println(numbers)  // [one, two, three, four]

集合的包含关系(类似数组和区间)

Pair & Triple

Pair,就是对,键值对的意思,包含两个元素,Triple则包含三个元素

Pair 创建键值和获取,解构

// 创建键值对的两种方式
val pair1 = "key" to "value"
val pair2 = Pair("key", "value")
println(pair1) // 输出结果:(key, value)
println(pair2) // 输出结果:(key, value)

//获取对应的元素,第一个和第二个
val first = pair1.first
val second = pair1.second
println(first) // 输出结果:key
println(second) // 输出结果:value

// 解构,创建一个x,y的解构,来存储键值对
val (x, y) = pair2
println(x) // 输出结果:key
println(y) // 输出结果:value

Triple 创建键值和获取,解构

// Triple 包含三个元素, 使用方法和Pair一样
val triple = Triple("key", 2, 3.0)
val first = triple.first
val second = triple.second
val third = triple.third
val (x, y, z) = triple
println(first) // 输出结果:key
println(second) // 输出结果:2
println(third) // 输出结果:3.0
println(x) // 输出结果:key
println(y) // 输出结果:2
println(z) // 输出结果:3.0

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Kotlin 集合框架 的相关文章

随机推荐

  • 正则表达式 匹配以特定字符串开头 到任意第一个字符中间的空格

    lt p style text indent 2em S 正则表达式 匹配以特定字符串开头 到任意第一个字符中间的空格 lt p p style text indent 2em u4e00 u9fa5 正则表达式 匹配以特定字符串开头 到任
  • 2021年的保研之旅总结

    保研之旅 个人情况介绍 1 学校 末流211 2 专业 信息管理与信息系统 信管算管理学位 保研的时候有的时候会被认为是跨保的 3 绩点 1 36 4 比赛获奖 没有什么拿得出手的获奖 只有一些小奖 全国大学生物联网设计竞赛全国一等奖 美国
  • robotframework-ride安装注意点

    欢迎关注 无量测试之道 公众号 回复 领取资源 Python编程学习资源干货 Python Appium框架APP的UI自动化 Python Selenium框架Web的UI自动化 Python Unittest框架API自动化 资源和代码
  • Server2008R2:由于没有远程桌面授权服务器可以提供许可证,远程会话被中断.的解决方法,求大神们指导

    出现 由于没有远程桌面授权服务器可以提供许可证 远程会话被中断 问题是因为微软默认的远程登录只提供120天的使用期限 解决该问题的具体步骤如下 1 打开运行 在运行中输入注册表命令 regedit 然后回车通过命令打开注册表对话框 2 在注
  • 获取windows中活跃的Com口

    获取windows中活跃的Com口 记录于2021年11月9日 今天对我来说是个很特殊的一天 母胎SOLO二十一周年 无奈 Orz 闲暇之余写下此文章 记录一下我的日常 文章目录 获取windows中活跃的Com口 前言 一 如何寻找活跃C
  • “另一个程序正在使用此文件,进程无法访问”的解决方法

    另一个程序正在使用此文件 进程无法访问 的解决方法 参考文章 1 另一个程序正在使用此文件 进程无法访问 的解决方法 2 https www cnblogs com shiningrise archive 2012 12 02 279812
  • apache 2.4 配置php,Apache2.4 PHP 配置

    Apache2 4服务器 http www apachehaus com cgi bin download plx APACHE24VC14 64位 http www apachehaus com cgi bin download plx
  • Vue创建Demo项目

    Vue创建Demo项目 Vue 发音为 vju 类似 view 是一款用于构建用户界面的 JavaScript 框架 它基于标准 HTML CSS 和 JavaScript 构建 并提供了一套声明式的 组件化的编程模型 帮助你高效地开发用户
  • 魔兽怀旧服联盟服务器不稳定,魔兽世界怀旧服上次被联盟攻击至少三个月前,“单边服”何去何从...

    游戏中我们是朋友 聊天侃地 在这里我们可以无拘无束的发言 不会有任何人阻挠 还有大家最喜欢吐槽的小编 请把口水收集好 随时准备和小编一起吐槽 魔兽世界怀旧服上次被联盟攻击至少三个月前 单边服 何去何从 今天公会一个人表示他被联盟杀了 大家都
  • React性能优化的手段有哪些

    1 使用纯组件 2 使用 React memo 进行组件记忆 React memo 是一个高阶组件 对 于相同的输入 不重复执行 3 如果是类组件 使用 shouldComponentUpdate 这是在重新渲染组件之前触发的其中一个生命周
  • 21. 成语接龙

    小张非常喜欢与朋友们玩成语接龙的游戏 但是作为 文化沙漠 的小张 成语的储备量有些不足 现在他的大脑中存储了m个成语 成语中的四个汉字都用一个1000000以内的正整数来表示 现在小张的同学为了考验他给出了他一个成语做开头和一个成语做结尾
  • HDFS的基础练习--新建目录

    实验 1 在HDFS的 上创建10目录 data01 data10 在浏览器上查看 2 在HDFS data03下递归创建 data05 data06 data07 递归创建 使用命令 hdfs fs mkdir p xx1 xx2 xx3
  • IDEA菜单栏不见了怎么办

    开始时候我的IDEA主菜单不见了 解决方法 打开Idea 按两次shift 并在弹出框内的搜索框里输入 view 然后往下拉 找图里的这个View 点击它 会弹出新的框 然后就 这样主菜单栏就出来了
  • SpringBoot 基础

    1 认识Spring Boot Spring 不同于一般框架 它是一个聚合的框架 通过Spring 框架可以使Java 更为便捷和系统化 Java web 中最为使用的框架为 Spring Framework Spring boot 是 S
  • python中使用apscheduler二步简单完成定时任务设置,用于自动化任务的创建,无人值守后台任务创建

    一 apscheduler的安装 首先需要安装pip 打开CMD输入pip install apscheduler 安装apscheduler模块 安装过程如下图 二 导入apscheduler包 设置参数与需要执行的脚本 coding u
  • Pytorch从0实现Transformer

    文章目录 摘要 一 构造数据 1 1 句子长度 1 2 生成句子 1 3 生成字典 1 4 得到向量化的句子 该阶段总程序 二 位置编码 2 1 计算括号内的值 2 2 得到位置编码 三 多头注意力 3 1 self mask 摘要 Wit
  • Elasticsearch笔记(七):聚合查询

    聚合框架有助于根据搜索查询提供聚合数据 聚合查询是数据库中重要的功能特性 ES作为搜索引擎兼数据库 同样提供了强大的聚合分析能力 它基于查询条件来对数据进行分桶 计算的方法 有点类似于 SQL 中的 group by 再加一些函数方法的操作
  • 高薪全栈工程师必备 Linux 基础

    https mp weixin qq com s biz MzI0MTQwMTMyOQ tempkey OTkzX0xtOTVOZkJQbjVQSnhQaWdFcU5pTXZiZ3BvRW5DaDNiaGg5MXJDdGVCSTdkSlFU
  • 【转载】TCP的seq和ack号计算方法

    seq和ack号存在于TCP报文段的首部中 seq是序号 ack是确认号 大小均为4字节 注意与大写的ACK不同 ACK是6个控制位之一 大小只有一位 仅当 ACK 1 时ack字段才有效 建立 TCP 连接后 所有报文段都必须把 ACK
  • Kotlin 集合框架

    集合概述 Kotlin 标准库提供了一整套用于管理集合的工具 集合是可变数量 可能为零 的一组条目 各种集合对于解决问题都具有重要意义 并且经常用到 集合通常包含相同类型的一些 数目也可以为零 对象 集合中的对象称为元素或条目 例如 一个系