2015-07-05 167 views
7

爲什麼lazy在這裏使用?Swift中的懶惰

extension SequenceType { 
    func mapSome<U>(transform: Generator.Element -> U?) -> [U] { 
     var result: [U] = [] 
     for case let x? in lazy(self).map(transform) { 
      result.append(x) 
     } 
     return result 
    } 
} 

這個擴展需要一個轉換函數返回一個可選的,並且只返回值的數組,並沒有轉化爲無

爲什麼不直接使用self.map(transform)?這裏需要懶惰嗎?

+0

順便說一句,'flatMap (transform:Generator.Element - > U?) - > [U]'現在可以在Swift 2標準庫中使用了:) – jtbandes

回答

11

它避免了創建中間數組。

self.map(transform) 

返回陣列含有 所有序列元素的轉變,這將隨後被遍歷以建立與非零元素 所得陣列的結果。

lazy(self).map(transform) 

序列轉化的元件的,然後將其 遍歷來獲得非零元素。在枚舉期間計算變換元素 。 (在懶序列next() 每個呼叫通過變換原始序列的下一 元件產生一種元素。)

兩種方法工作。對於大型序列,惰性方法可能會執行更好的 ,但這可能取決於許多因素(數組的大小 ,元素是值還是引用類型,複製數組元素的代價如何)。對於小型陣列 ,由於額外的開銷,延遲方法可能會變慢。在具體的應用中,使用儀器分析將幫助決定使用哪種方法。

+1

我的(不可否認的)性能測試表明,懶惰和非懶惰對小數組執行完全相同,但是這種懶惰確實會給較大的因此值得包括(特別是在像這樣的庫函數中)。有趣的是,現在''flatMap'現在有兩個相同的邏輯,表現比兩者都差。 –

+0

@AirspeedVelocity:這很有趣,謝謝你的反饋。 –

+0

有趣的是,我得到了相反的結果!?請參閱下面的答案。 – Qbyte

5

由於Martin R提到lazy()避免了創建中間數組。但是,如果我比較不同大小的數組上的函數的執行時間,則會發現lazy()「僅」快了10%。

有趣的是,您發現lazy()適用於元素少於200個的陣列,速度提高2倍,獲得的元素幾乎與沒有轉換的函數相同(速度提高10%)。

(測試和Xcode 6.4和Xcode的7全局函數和協議擴展在操場(編譯)源文件)

所以lazy()寧願被用於Sequences,你不知道它是有限的。然後,for循環有可能與breakreturn使用:

for element in lazy(sequence).map{ ... } { 
    if element == 1000 { 
     break 
    } 
    // use element 
} 

如果你調用一個無限Sequence(如1,2,3 ...)執行地圖也將是無限的。由於lazy()轉換和執行得到「延遲」,因此如果在最後一個元素之前跳出循環,則可以更有效地處理「大」和無限序列。