【Kotlin】函数式编程 ③ ( 早集合与惰性集合 | 惰性集合-序列 | generateSequence 序列创建函数 | 序列代码示例 | take 扩展函数分析 )
创始人
2025-05-28 05:05:36
0

文章目录

  • 一、及早集合与惰性集合
  • 二、惰性集合-序列
  • 三、generateSequence 序列创建函数
    • 1、函数简介
    • 2、函数原型
    • 3、函数简介
    • 4、使用示例
  • 四、序列代码示例
    • 1、使用传统的函数式编程实现
    • 2、使用序列 Sequence 实现
    • 3、take 扩展函数分析





一、及早集合与惰性集合



及早集合 与 惰性集合 :

  • 及早集合 : Eager Collection , 指的是 List , Map , Set 等集合 , 这些集合创建后 , 需要 将元素提前存储到集合中 , 然后才能访问 ;
  • 惰性集合 : Lazy Collection , 在 集合刚创建时不必将集合元素放进去 , 当使用这些元素时才生成 , 这些 集合元素按需产生 ;

在 惰性集合 中 集合元素的 初始化 是 惰性初始化 ;





二、惰性集合-序列



Kotlin 中提供了一个 惰性集合 , 称为 序列 Sequence ;

在 序列 中 , 不记录元素个数 , 也 不对其内容进行排序 , 在该

序列中的元素 是由 数据源 产生的 , 其元素个数 可能有无限多个 ;





三、generateSequence 序列创建函数




1、函数简介


“generateSequence” 函数 是 Kotlin 标准库 中的一个函数,属于 Kotlin 的 序列生成器

“generateSequence” 函数 可以生成一个 惰性序列,并且支持从指定的序列中生成元素。

生成的序列是惰性的,意味着 请求元素时,才会 生成相应的元素。这使得开发者可以在 不需要处理整个序列的情况下,处理序列中的元素。


2、函数原型


Kotlin 提供的 " generateSequence " 标准库函数 , 原型如下 :

/*** 返回由起始值[seed]和函数[nextFunction]定义的序列,每次迭代时,该函数被调用以根据前一个值计算下一个值** 序列产生值,直到遇到第一个null值。* 如果[seed]是null,则生成一个空序列。* * 该序列可以多次迭代,每次都从[seed]开始。** @see kotlin.sequences.sequence** @sample samples.collections.Sequences.Building.generateSequenceWithSeed*/
@kotlin.internal.LowPriorityInOverloadResolution
public fun  generateSequence(seed: T?, nextFunction: (T) -> T?): Sequence =if (seed == null)EmptySequenceelseGeneratorSequence({ seed }, nextFunction)
  • seed: T? 参数 : 该参数是 序列的第一个元素值 , 初始值 , 又称为随机种子 ;
  • nextFunction: (T) -> T? 参数 : 该参数是一个 匿名函数 / Lambda 表达式 / 闭包 , 可以 根据前一个值计算出下一个值 ;

3、函数简介


Kotlin 的 generateSequence 函数是一种 生成序列 的方法,它可以生成 可迭代的、有限或无限的序列


generateSequence 函数 接收两个参数:

  • 起始值 seed
  • 生成下一个值的 匿名函数 nextFunction。

每次迭代时,nextFunction 都会被调用以生成下一个值,并且该序列会不断生成值,直到遇到第一个 null 值。如果起始值为 null,那么将会生成一个空序列。

该序列可以 多次迭代,每次都从起始值开始。这是因为 generateSequence 返回一个实现了 Sequence 接口的对象,这意味着你可以 在多次迭代之间重用该序列。

通过使用 generateSequence,你可以简化代码,提高可读性和可维护性,并且可以 生成更复杂的序列,如斐波那契数列、自然数序列等。


4、使用示例


使用方法 : 使用 “generateSequence” 函数 并 传递一个函数作为参数 ; 函数必须返回 “Nullable” 类型的值,当序列不再生成元素时返回 “null”。

“generateSequence” 函数 是一种高效且灵活的 生成序列 的方法,它可以用于许多应用程序,如 生成指定数量的元素、生成无限循环的序列等。


示例 : 以下代码生成一个从 1 开始的整数序列:

val sequence = generateSequence(1) { it + 1 }
println(sequence.take(10).toList()) // prints [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]




四、序列代码示例



取 从 2 开始的 前 20 个 素数 ;


1、使用传统的函数式编程实现


代码示例 : 下面的代码中 , 从 1 ~ 1000 的区间内查找素数 , 必须将 1000 个元素的集合生成出来 , 然后逐个遍历 ;

/*** 为 Int 定义扩展函数, 判断接收者是否是素数*/
fun Int.isPrimeNumber(): Boolean {// number 参数是被遍历的 接收者集合 的 受检元素// 符合下面的要求 才会被放入新集合// 遍历时每个 受检元素 都要 被 [2..number - 1] 区间的数值进行遍历val isPrimeNumber = (2..this - 1)// 计算 number 与 [2..number - 1] 区间中的数值 相除的 余数// 也就是验证 是否 只有 1 和 其本身 可以被其整除.map { this % it }// 通过 map 变换计算出的余数// 不能出现 余数 为 0 的情况// 一旦出现 就返回 false.none{it == 0}return isPrimeNumber
}fun main() {val numbers = (2..1000).toList()   // 将 IntRange 转为 List 集合.filter { it.isPrimeNumber() }  // 筛选出集合中是素数的人.take(20) // 从筛选出来的数值中取 20 个元素println(numbers)
}

执行结果 :

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]

在这里插入图片描述


2、使用序列 Sequence 实现


使用传统方式实现素数查找 , 如 : 从 1 ~ 1000 的区间内查找素数 , 必须将 1000 个元素的集合生成出来 , 然后逐个遍历 ;

如果使用 序列 Sequence 实现 , 则 只需要实现需要的部分 , 没有遍历的元素不会生成 ;


代码示例 :

/*** 为 Int 定义扩展函数, 判断接收者是否是素数*/
fun Int.isPrimeNumber(): Boolean {// number 参数是被遍历的 接收者集合 的 受检元素// 符合下面的要求 才会被放入新集合// 遍历时每个 受检元素 都要 被 [2..number - 1] 区间的数值进行遍历val isPrimeNumber = (2..this - 1)// 计算 number 与 [2..number - 1] 区间中的数值 相除的 余数// 也就是验证 是否 只有 1 和 其本身 可以被其整除.map { this % it }// 通过 map 变换计算出的余数// 不能出现 余数 为 0 的情况// 一旦出现 就返回 false.none{it == 0}return isPrimeNumber
}fun main() {val numbers = generateSequence(2) { it + 1 }    // 设置初始值为 2 , 然后每次值自增 1.filter { it.isPrimeNumber() }  // 遍历序列元素 , 查询是否是素数.take(20)   // 取前 20 个素数println(numbers)
}

执行结果 :

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]

在这里插入图片描述


3、take 扩展函数分析


下面是 普通集合 调用的 take 扩展函数 原型序列 Sequence 调用的 take 扩展函数 的对比 , 两个 函数 是不同的 , take 函数决定了 取值的个数 ;

序列 Sequence 调用 take 函数时 , take 函数调用了序列的部分内容 , 决定了 序列 Sequence 的执行次数 , 生成多少元素 , 如 : 上述代码示例中 take 函数取够了 20 个素数 , 之后 Sequence 就不再继续生成后续元素了 ;


普通集合 调用的 take 扩展函数 原型 和 序列 Sequence 调用的 take 扩展函数 的对比 :

  • 普通集合 调用的 take 扩展函数 原型 :
/*** Returns a list containing first [n] elements.* * @throws IllegalArgumentException if [n] is negative.* * @sample samples.collections.Collections.Transformations.take*/
public fun  Iterable.take(n: Int): List {require(n >= 0) { "Requested element count $n is less than zero." }if (n == 0) return emptyList()if (this is Collection) {if (n >= size) return toList()if (n == 1) return listOf(first())}var count = 0val list = ArrayList(n)for (item in this) {list.add(item)if (++count == n)break}return list.optimizeReadOnlyList()
}
  • 序列 Sequence 调用的 take 扩展函数 原型 :
/*** Returns a sequence containing first [n] elements.** The operation is _intermediate_ and _stateless_.* * @throws IllegalArgumentException if [n] is negative.* * @sample samples.collections.Collections.Transformations.take*/
public fun  Sequence.take(n: Int): Sequence {require(n >= 0) { "Requested element count $n is less than zero." }return when {n == 0 -> emptySequence()this is DropTakeSequence -> this.take(n)else -> TakeSequence(this, n)}
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...