2015-07-05 122 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()转换和执行得到“延迟”,因此如果在最后一个元素之前跳出循环,则可以更有效地处理“大”和无限序列。