Kotlin基础知识(八)——惰性集合操做:序列

前几节中,你看到了不少链式集合函数调用的样子,好比map和filter。这些函数会及早地建立中间集合,也就是说每一步的中间结果都被村粗在一个临时列表。markdown

序列给了你执行这些操做的另外一种选择,能够避免建立这些临时中间对象。函数

people.map(Person::name).filter { it.startsWith("A") }
复制代码

Kotlin标准库参考文档有说明,filtermap都会返回一个列表。这意味着上面例子中的链式调用会建立两个列表:一个保持filter函数的结果,另外一个保存map函数的结果。性能

为了提升效率,能够把操做变成使用序列,而不是直接使用集合:spa

// 把初始集合转换成序列
people.asSequence()
         // 序列支持和集合同样的API
        .map(Person::name)
        .filter { it.startsWith("A") }
        //把结果序列转换回序列
        .toList()
复制代码

Kotlin惰性集合操做的入口就是***Sequence接口。这个接口表示的就是一个能够逐个列举元素的元素序列Sequence只提供了一个方法,iterator***,用来从序列中获取值。code

*Sequence*接口的强大之处在于其操做的实现方法。序列中的元素求值是惰性的。所以,可使用序列更高效地对集合元素执行链式操做,而不须要建立额外的集合来保存过程当中产生的中间结果。orm

先调用扩展函数asSequence把任意集合转换为序列,调用toList来作反向的转换。对象

  • 为啥要把序列转换回集合?用序列代替集合不是更方便吗?特别是它们还有这么多优势。

答案:有的时候是这样。若是只须要迭代序列中的元素,能够直接使用序列。若是你要用其余的API方法,好比用下标访问元素,则需将序列转换成列表。接口

1、执行序列操做:中间和末端操做

序列操做分为两类:中间和末端。一次中间操做返回的是另外一个序列,这个新序列知道如何变换原始序列中的元素。而一次末端操做返回的是一个结果。文档

| ----- 中间操做 ----- |
sequence.map { ... }.filter { ... }.toList()
                                  |-末端操做-|
复制代码

中间操做始终都是惰性的string

  • 缺乏末端操做的示例:
>>> listOf(1,2,3,4).asSequence()
            .map { print("map($it)"); it * it }
            .filter { print("filter($it)"); it % 2 == 0 }
复制代码

执行这段代码并不会在控制台上输入任何内容。这意味着map和filter变换被延期了,它们只有在获取结果的时候才会被应用。

  • 完整示例
>>> listOf(1,2,3,4).asSequence()
            .map { print("map($it)"); it * it }
            .filter { print("filter($it)"); it % 2 == 0 }
            .toList()

// 输出结果
map(1) filter(1) map(2) filter(4) map(3) filter(9) map(4) filter(16)
复制代码

这个例子中另一件值得注意的重要事情是计算执行的顺序(其会影响性能)。

2、建立序列

建立序列的方式:

  • asSequence()
  • generateSequence()
>>> val naturalNumbers = generateSequence(0) { it + 1 }
// numbersTo100是一个序列:[0, 1, 2, ... , 100]
>>> val numbersTo100 = naturalNumbers.takeWhile { it <= 100 }
>>> println(numbersTo100.sum())
5050
复制代码
相关文章
相关标签/搜索