kotlin中的Sequence与Iterable

Sequence与Iterable

Sequence(序列)提供与Iterable(迭代器)相同的拓展函数,他们处理数据的结果都一样,不一样的是处理数据的方法,Sequence是针对每一个元素去做所有执行操作,而Iterable是把每个执行操作都做一遍,根据上一个操作返回的集合做下一步操作,如对所有元素执行filter后再对返回的集合做map操作。Sequence则是对第一个元素做全部操作后再跳到下一个元素。
下面根据kotlin官网给的例子
假定有一个单词列表。下面的代码过滤长于三个字符的单词,并打印前四个单词的长度。
下面是用Iterable输出的结果

fun main(){
    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]

我们可以看到先进行所有filter操作然后在进行所有map操作,最后再取前四个,具体步骤如下图一:
图一

可以看出如果我们只需要取前四个的话,再进行到over这个单词的时候就可以结束了,这样子反而多出来计算over后面单词的时间花销。
而Sequence就是解决这个问题的,用Sequence来写代码就是

fun main(){
    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())
}
//输出结果
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用了18步,Iterable则用了23步,只需判断出第四个符合的单词就可以结束过程了,不用考虑后面的单词。同时我们可以发现是先输出的提示语句,在输出"filter: $it"这个步骤,这就说明了Sequnece的惰性,他是在你需要的时候才进行实际计算。

选择Sequence和Iterable的场景

这里引用Kotlin中是应该使用序列(Sequences)还是集合(Lists)?的结论

1、当不需要中间操作时,使用List
2、当仅仅只有map操作时,使用sequence
3、当仅仅只有filter操作时,使用List
4、如果末端操作是first时,使用sequence

如果是量级比较小的集合元素,作为参数返回给其他函数的时候用list,因为每次迭代Sequences的时候都会重新计算一遍,函数可能多次遍历计算。
当数据集量级大的时候,Sequence就会占优势,因为他惰性操作节约了时间,又没有如Iterable计算时产生的中间集合,节约了空间。

generateSequence

generateSequence是根据提供的函数来构建序列,初始值可给可不给,当返回null时就会停止,不然会一直生成序列,下面代码是根据33为起始值,一直加1并选择前四个奇数

fun main(){
    val number = generateSequence(33){it+1}
    println(number.filter{it and 1 == 1}.take(4).toList())
    //println(number.filter{it and 1 == 1}.toList()) //此序列将会是无限的,不会停止
}
//输出结果
[33, 35, 37, 39]

如果不选择前四个,那么他会一直生成下去,永远不会结束循环,如果要创建有序的就自己设置一个终止条件来返回null。

你可能感兴趣的:(kotlin中的Sequence与Iterable)