1.迭代器

  对于遍历集合元素,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)
}

  1.1 List迭代器

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

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

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

  1.2 可变迭代器

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

val numbers = mutableListOf("one", "two", "three", "four")
val mutableIterator = numbers.iterator()
mutableIterator.next()
mutableIterator.remove()
println("After removal: $numbers")

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

val numbers = mutableListOf("one", "four", "four")
val mutableListIterator = numbers.listIterator() mutableListIterator.next()
mutableListIterator.add("two")
mutableListIterator.next()
mutableListIterator.set("three")
println(numbers)

2.区间与数列

  Kotlin 可通过调用 kotlin.ranges 包中的 rangeTo() 函数及其操作符形式的 .. 轻松地创建两 个值的区间。通常,rangeTo() 会辅以 in 或 !in 函数。

if(i in 1..4){ //等同于1<=i&&i<=4
print(i)
}

  整数类型区间(IntRange、LongRange、CharRange)还有一个拓展特性:可以对其进行迭代。这些区间也是相应整数类型的等差数列。这种区间通常用于 for 循环中的迭代。

for (i in 1..4) print(i)

  要反向迭代数字,请使用 downTo 函数而不是 .. 。

for (i in 4 downTo 1) print(i)

  也可以通过任意步⻓(不一定为 1 )迭代数字。这是通过 step 函数完成的。

for (i in 1..8 step 2) print(i) //输出 1357
println()
for (i in 8 downTo 1 step 2) print(i)//输出 8642

  要迭代不包含其结束元素的数字区间,请使用 until 函数:

for (i in 1 until 10) { // i in [1, 10), 10被排除
print(i)
}

  2.1 区间

    区间从数学意义上定义了一个封闭的间隔:它由两个端点值定义,这两个端点值都包含在该区间内。区间是为可比较类型定义的:具有顺序,可以定义任意实例是否在两个给定实例之间的区间内。区间的主要操作是 contains,通常以 in 与 !in 操作符的形式使用。

    要为类创建一个区间,请在区间起始值上调用 rangeTo() 函数,并提供结束值作为参数。 rangeTo() 通常以操作符 .. 形式调用。

val versionRange = Version(1, 11)..Version(1, 30)
println(Version(0, 9) in versionRange)
println(Version(1, 20) in versionRange)

  2.2 数列

    如上个示例所示,整数类型的区间(例如 Int 、Long 与 Char )可视为等差数列。在 Kotlin 中,这些数 列由特殊类型定义:IntProgression、LongProgression 与 CharProgression。

    数列具有三个基本属性:first 元素、last 元素和一个非零的 step 。首个元素为 first ,后续元素是前一个元素加上一个 step。以确定的步⻓在数列上进行迭代等效于Java/JavaScript中基于索 引的 for 循环

for (int i = first; i <= last; i += step) {
// ......
}

    通过迭代数列隐式创建区间时,此数列的 first 与 last 元素是区间的端点,step 为 1

for (i in 1..10) print(i)

    要指定数列步⻓,请在区间上使用 step 函数

for (i in 1..8 step 2) print(i)

    数列的 last 元素是这样计算的:

— 对于正步⻓:不大于结束值且满足 (last - first) % step == 0 的最大值。
— 对于负步⻓:不小于结束值且满足 (last - first) % step == 0 的最小值。

    因此,last 元素并非总与指定的结束值相同

for (i in 1..9 step 3) print(i) // 最后一个元素是 7

    要创建反向迭代的数列,请在定义其区间时使用 downTo 而不是 .. 。

for (i in 4 downTo 1) print(i)

    数列实现 Iterable<N>,其中 N 分别是 Int、Long 或 Char,因此可以在各种集合函数(如map、filter 与其他)中使用它们

println((1..10).filter { it % 2 == 0 })

3.序列

  除了集合之外,Kotlin 标准库还包含另一种容器类型⸺序列(Sequence<T>)。序列提供与 Iterable 相同的函数,但实现另一种方法来进行多步骤集合处理。

  当 Iterable 的处理包含多个步骤时,它们会优先执行:每个处理步骤完成并返回其结果⸺中间集合。在此集合上执行以下步骤。反过来,序列的多步处理在可能的情况下会延迟执行:仅当请求整个处理链的结果时才进行实际计算。

  操作执行的顺序也不同:Sequence 对每个元素逐个执行所有处理步骤。反过来,Iterable 完成整 个集合的每个步骤,然后进行下一步。

  因此,这些序列可避免生成中间步骤的结果,从而提高了整个集合处理链的性能。但是,序列的延迟性质 增加了一些开销,这些开销在处理较小的集合或进行更简单的计算时可能很重要。因此,应该同时考虑 使用 Sequence 与 Iterable,并确定在哪种情况更适合

4.构造

  4.1 由元素,要创建一个序列,请调用 sequenceOf() 函数,列出元素作为其参数

val numbersSequence = sequenceOf("four", "three", "two", "one")

  4.2 由 Iterable,如果已经有一个 Iterable 对象(例如 List 或 Set ),则可以通过调用 asSequence() 从而创建一个序列。

val numbers = listOf("one", "two", "three", "four")
val numbersSequence = numbers.asSequence()

  4.3 由函数,创建序列的另一种方法是通过使用计算其元素的函数来构建序列。要基于函数构建序列,请以该函数作 为参数调用 generateSequence()。(可选)可以将第一个元素指定为显式值或函数调用的结果。当

提供的函数返回 null 时,序列生成停止。因此,以下示例中的序列是无限的

val oddNumbers = generateSequence(1) { it + 2 } // `it` 是上一个元素
println(oddNumbers.take(5).toList())
//println(oddNumbers.count()) // 错误:此序列是无限的。

    要使用 generateSequence() 创建有限序列,请提供一个函数,该函数在需要的最后一个元素之后 返回 null

val oddNumbersLessThan10 = generateSequence(1) { if (it < 10) it + 2 else null }
println(oddNumbersLessThan10.count())

  4.4 由组块,最后有一个函数可以逐个或按任意大小的组块生成序列元素sequence( )函数.此函数采用一个lambda 表达式,其中包含 yield() 与 yieldAll() 函数的调用。它们将一个元素返回给序列使用 者,并暂停 sequence() 的执行,直到使用者请求下一个元素。yield() 使用单个元素作为参 数;yieldAll() 中可以采用 Iterable 对象、Iterable 或其他 Sequence 。yieldAll() 的Sequence 参数可以是无限的。当然,这样的调用必须是最后一个:之后的所有调用都永远不会执行

val oddNumbers = sequence {
yield(1)
yieldAll(listOf(3, 5))
yieldAll(generateSequence(7) { it + 2 })
}
println(oddNumbers.take(5).toList())

5.序列操作

  关于序列操作,根据其状态要求可以分为以下几类:

— 无状态操作不需要状态,并且可以独立处理每个元素,例如map()或filter()。无状态操作还可能需要少量常数个状态来处理元素,例如 take() 与 drop()。
— 有状态操作需要大量状态,通常与序列中元素的数量成比例

  如果序列操作返回延迟生成的另一个序列,则称为 中间序列。否则,该操作为 末端 操作。末端操作的示 例为 toList() 或 sum()。只能通过末端操作才能检索序列元素。

  序列可以多次迭代;但是,某些序列实现可能会约束自己仅迭代一次。其文档中特别提到了这一点。

6.序列处理示例

  我们通过一个示例来看 Iterable 与 Sequence 之间的区别

  6.1 Iterable,假定有一个单词列表。下面的代码过滤⻓于三个字符的单词,并打印前四个单词的⻓度

val words = "The quick brown fox jumps over the lazy dog".split(" ")
val lengthsList = words.filter { println("filter: $it"); it.length > 3 }
.map { println("length: ${it.length}"); it.length }.take(4)
println("Lengths of first 4 words longer than 3 chars:")
println(lengthsList)

  运行此代码时,会看到 filter() 与 map() 函数的执行顺序与代码中出现的顺序相同。首先,将看到 filter :对于所有元素,然后是 length :对于在过滤之后剩余的元素,然后是最后两行的输出。列表处理如下图

  6.2 Sequence,现在用序列写相同的逻辑

val words = "The quick brown fox jumps over the lazy dog".split(" ")
// 将列表转换为序列
val wordsSequence = words.asSequence() val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }
.map { println("length: ${it.length}"); it.length }
.take(4) println("Lengths of first 4 words longer than 3 chars") // 末端操作:以列表形式获取结果。
println(lengthsSequence.toList())

  此代码的输出表明,仅在构建结果列表时才调用 filter() 与 map() 函数。因此,首先看到文本 “Lengths of..” 的行,然后开始进行序列处理。请注意,对于过滤后剩余的元素,映射在过滤下一个元素之前执行。当结果大小达到 4 时,处理将停止,因为它是 take(4) 可以返回的最大大小

  序列处理如下图:在此示例中,序列处理需要 18 个步骤,而不是 23 个步骤来执行列表操作

  

kotlin集合——>迭代器、区间与数列的更多相关文章

  1. Kotlin集合——Set集合

    Kotlin集合——Set集合 转 https://www.jianshu.com/p/3c95d7729d69   Kotlin的集合类由两个接口派生:Collection和Map. Kotlin的 ...

  2. 轻量级“集合”迭代器-Generator

    Generator是PHP 5.5加入的新语言特性.但是,它似乎并没有被很多PHP开发者广泛采用.因此,在我们了解PHP 7对Generator的改进之前,我们先通过一个简单却显而易见的例子来了解下G ...

  3. 集合迭代器快速失败行为及CopyOnWriteArrayList

    以下内容基于jdk1.7.0_79源码: 什么是集合迭代器快速失败行为 以ArrayList为例,在多线程并发情况下,如果有一个线程在修改ArrayList集合的结构(插入.移除...),而另一个线程 ...

  4. Java基础知识强化之集合框架笔记09:Collection集合迭代器使用的问题探讨

    1.Collection集合迭代器使用的问题探讨: (1)问题1:能用while循环写这个程序,我能不能用for循环呢?                  可以使用for循环替代. (2)问题2:不要 ...

  5. 上手并过渡到PHP7(5)——轻量级“集合”迭代器-Generator

    轻量级“集合”迭代器-Generator泊学视频链接泊阅文档链接Generator是PHP 5.5加入的新语言特性.但是,它似乎并没有被很多PHP开发者广泛采用.因此,在我们了解PHP 7对Gener ...

  6. Kotlin集合——List集合

    Kotlin集合——List集合 转 https://www.jianshu.com/p/3f3bb4943638   List集合的最大特征就是集合元素都有对应的顺序索引.List集合允许使用重复元 ...

  7. Kotlin集合——Map集合

    Kotlin集合——Map集合 转 https://www.jianshu.com/p/da5cc9072f1e Kotlin的Map集合用于保存key-value对,其也被分为可变的和不可变的. 一 ...

  8. Java基础知识强化之集合框架笔记19:List集合迭代器使用之 并发修改异常的产生原因 以及 解决方案

    1. 我有一个集合,如下,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现. ConcurrentModi ...

  9. -1-3 java集合框架基础 java集合体系结构 Collection 常用java集合框架 如何选择集合 迭代器 泛型 通配符概念 Properties 集合 迭代器

    集合又称之为容器存储对象的一种方式 •数组虽然也可以存储对象,但长度是固定的:显然需要可变长度的容器 集合和数组的区别?                 A:长度区别                  ...

  10. java集合迭代器

    一.Java中有一个设计模式是迭代器模式 1.迭代器模式定义迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示. 2.迭代器模式概述Java集合框 ...

随机推荐

  1. 【WSDL】01 JAX-WS 入门案例

    去年这个时候工作遇见时暂时总结的笔记: https://www.cnblogs.com/mindzone/p/14777493.html 当时也不是很清楚,直到最近前同事又遇上了这项技术, 除了WSD ...

  2. 【Oracle】Windiws-11G 安装

    教程参考: https://jingyan.baidu.com/article/363872eccfb9266e4aa16f5d.html 安装包文件目录: 注意,使用[管理员运行此文件] 然后稍等许 ...

  3. 【FastDFS】05 Java程序测试上传

    创建普通Maven工程 导入所需依赖坐标: <dependencies> <!-- https://mvnrepository.com/artifact/net.oschina.zc ...

  4. 告别手动调度,海豚调度器 3.1.x 集群部署让你轻松管理多机!

    转载自第一片心意 1 前言 由于海豚调度器官网的集群部署文档写的较乱,安装过程中需要跳转到很多地方进行操作,所以自己总结了一篇可以直接跟着从头到尾进行操作的文档,以方便后续的部署.升级.新增节点.减少 ...

  5. 前端界面显示当前时间的Vue代码

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. 高考志愿填报指南:使用AI阅读工具ChatDOC搭建专业、好用、免费的AI高考志愿填报系统

    高考志愿填报指南:使用 ChatDOC 搭建专业.好用.免费的 AI 高考志愿填报系统 不说废话,直接上干货.针对高考志愿填报,这篇文章能为你提供以下内容:高考志愿填报专业数据.高考志愿填报分析思路. ...

  7. 设计模式之cglib动态代理

    什么是动态代理呢?动态代理就是在java进程运行时,通过字节码技术,动态的生成某个类的代理类.在这个代理类中,我们可以做一些额外的操作,一方面仍然保持原有的方法的能力,另外一方面还增强了这些能力.听着 ...

  8. Win32 API 读取文件

    昨天又用Win32来读取文件的时候,又出现了字符编码的问题. 用TCHAR字符来写文件呢,用系统的记事本打开是乱码. 用CHAR字字符来写呢,在读取汉字的时候后面有一串乱码, 用CHAR[]数组读取就 ...

  9. windows server 2008 和 win10 双系统安装 ,bios引导 uefi引导总结(可能只适应于我的品牌的笔记本电脑,仅做记录给自己方便下次装系统)

    之前电脑是装好了这两个系统并且正常开机的,bios引导的,也就是开机的时候出现黑框框,上下两个系统选项的那种. 后来在windows server2008里面不小心把win10的盘符给删了一些文件.. ...

  10. chroot 整理

    chroot 是什么? 就是change root directory ,比如默认是 /, 可以用这个chroot 把 / 换成其他指定的目录 chroot 干什么的? 增加了系统的安全性,限制了用户 ...