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
複製代碼
相關文章
相關標籤/搜索