深色模式
Kotlin 集合之 序列 Sequence
序列和迭代器的差别
对Iterable
遍历执行多步操作时,会先对所有元素执行一个步骤,将结果保存到中间集合中,然后再对中间集合中所有元素执行下一个步骤,以此类推。相当于,所有元素被并行处理。
对Sequence
遍历执行多步操作时,会对一个元素执行所有步骤,然后再对下一个元素执行所有步骤,以此类推。相当于,所有元素被串行处理。
序列的创建方式
通过元素创建
kotlin
val s1 = sequenceOf(1, 2, 3)
通过Iterable
创建
kotlin
val list = listOf(1,2,3)
val s2 = list.asSequence()
通过generateSequence()
函数创建
该函数有3种重载,都是用来定义如果生成第1个元素和下一个元素。当序列元素的计算函数返回null
时,序列的生成过程会停止。
generateSequence(nextFunction: () -> T?): Sequence<T>
generateSequence(seed: T?, nextFunction: (T) -> T?): Sequence<T>
generateSequence(seedFunction: () -> T?, nextFunction: (T) -> T?): Sequence<T>
通过sequence()
创建
sequence()
函数可以逐个生成序列元素,这个函数的参数是一个lambda
表达式,其中包括对yield()
函数和yieldAll()
函数的调用。这些函数会将元素返回给序列的使用者,然后暂停 sequence()
函数的执行,直到序列使用者请求下一个元素。
yield()
的参数是单个元素。yieldAll()
的参数可以是一个Iterable
对象,或一个Iterator
,或另一个Sequence
。yieldAll()
函数的Sequence
参数可以是无限的。如果Sequence
参数是无限的,yieldAll()
必须出现在lambda
的最末尾,否则,后面的代码将没有机会执行。
有些语言,把这个叫生成器,比如 Python。
序列的操作
举个栗子🌰
假设有很多单词,我们要过滤长度超过3个字母的单词,然后打印前4个这种单词的长度。
使用Iterable
代码:
kotlin
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: The
filter: quick
filter: brown
filter: fox
filter: jumps
filter: over
filter: the
filter: lazy
filter: dog
length: 5
length: 5
length: 5
length: 4
length: 4
Lengths of first 4 words longer than 3 chars:
[5, 5, 5, 4]
执行步骤图解:
使用Sequence
代码:
kotlin
val words = "The quick brown fox jumps over the lazy dog".split(" ")
// 将 List 转换为序列
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")
// 终止操作: 以 List 形式获取结果
println(lengthsSequence.toList())
执行结果:
Lengths of first 4 words longer than 3 chars
filter: The
filter: quick
length: 5
filter: brown
length: 5
filter: fox
filter: jumps
length: 5
filter: over
length: 4
[5, 5, 5, 4]
代码执行图解:
使用Sequence
时的差异
filter()
、map()
和take()
这些操作,在调用toList()
后才开始执行。与上面Iterable
的🌰相比,是”lazy“的。- 当结果元素数量到达4个时,会停止处理,因为
take(4)
指定了最大元素数量。与上面Iterable
的🌰相比,节省了操作步骤。 - Sequence处理执行了 18 步,而使用Iterable时则需要 23 步。