序列(Sequence) VS 集合(Iterable)
举个例子:给定一个字符串,过滤长于三个字符的单词,并打印前四个单词的长度
Iterable写法:
fun main() {
val words = "The quick brown fox jumps over the lazy dog".split(" ")
val lengthsList = { println("filter: $it"); > 3 }
.map { println("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]
运行此代码时,会看到 filter() 与 map() 函数的执行顺序与代码中出现的顺序相同。 filter作用于所有元素,length作用于过滤之后剩余的元素,最后是两个println。
流程图:引用自官网 Sequence写法:
fun main() {
val words = "The quick brown fox jumps over the lazy dog".split(" ")
// 将列表转换为序列
val wordsSequence = ()
val lengthsSequence = { println("filter: $it"); > 3 }
.map { println("length: ${}"); }
.take(4)
println("Lengths of first 4 words longer than 3 chars")
// 末端操作:以列表形式获取结果。
println(())
}
>>> 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]
此代码的输出表明,仅在构建结果列表时才调用 filter() 与 map() 函数。 因此,首先看到文本 “Lengths of…” 的行,然后开始进行序列处理。 注意:对于过滤后剩余的元素,映射在过滤下一个元素之前执行。当结果大小达到 4 时,处理将停止,因为它是 take(4) 可以返回的最大大小。
流程图:引用自
在此示例中,序列处理需要 18 个步骤,而不是 23 个步骤来执行列表操作
总结: ①Sequence会对每个元素逐个执行所有操作步骤,因此能够有效减少中间步骤的执行,从而提高整个收集链的性能。 ②Sequence具备延迟性质,只有在请求整个处理链的结果时才进行实际计算,所以也具备一定的开销。这些开销在处理较小的集合或进行简单的计算时也许很重要
静态创建Sequence
// method one : 调用 sequenceOf() 方法,传入相应参数
val numSequence = sequenceOf("one","two","three")
// method two : 调用 asSequence()
val numbers = listOf("one", "two", "three", "four")
val numbersSequence = ()
// 使用 generateSequence() 创建
val numberSequence = generateSequence(1) { if (it + 2 < 10) it + 2 else null }
动态创建Sequence
调用sequence()函数,该函数接收一个lambda表达式,其中包含yield()和yieldAll()函数的调用。下面例子的写法解释一下:lambda表达式作为函数调用的最后一个实参时,可以放在括号外边。当lambda是函数唯一的实参时,还可以去掉调用代码中的空括号对(kotlin语法糖)
yield:礼让,即当前元素返回给sequence之后就暂停该sequence() 的执行,直到使用者请求下一个元素。 yield() 使用单个元素作为参数; yieldAll() 中可以采用 Iterable 对象、Iterable 或其他 Sequence。yieldAll() 的 Sequence 参数可以是无限的。 当然,这样的调用必须是最后一个:否则在这之后的所有调用都不会执行。//①
val oddNumbers = sequence {
yield(1)
yieldAll(listOf(3, 5))
yieldAll(generateSequence(7) { it + 2 })
}
println((12).toList())
>>> [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23]
解释一下注释①,意思就是如果无限产生数据的yieldAll()之后还有yield操作,将被忽视
val oddNumbers = sequence {
yield(1)
yieldAll(generateSequence(7) { it + 2 })
yieldAll(listOf(3, 5))
}
println((5).toList())
>>> [1, 7, 9, 11, 13]