为什么以及何时在Swift中使用lazy与Array?

Dee*_*ora 16 arrays lazy-evaluation swift

[1, 2, 3, -1, -2].filter({ $0 > 0 }).count // => 3

[1, 2, 3, -1, -2].lazy.filter({ $0 > 0 }).count // => 3
Run Code Online (Sandbox Code Playgroud)

添加lazy到第二个语句的优点是什么?根据我的理解,当使用lazy变量时,内存在使用时被初始化为该变量.在这种情况下它是如何有意义的?

在此输入图像描述

试图LazySequence更详细地了解其用途.我曾使用过的map,reduce并且filter功能上的序列,但从来没有对lazy序列.需要了解为何使用此功能?

vac*_*ama 29

lazy更改数组的处理方式.如果lazy未使用,则filter处理整个数组并将结果存储到新数组中.当lazy被使用时,序列或集合中的值的生成按需从下游功能.值不存储在数组中; 它们只是在需要时生产.

考虑一下这个修改过的例子,我用它reduce来代替count我们打印出发生的事情:

不使用lazy:

在这种情况下,在计算任何项目之前,将首先过滤所有项目.

[1, 2, 3, -1, -2].filter({ print("filtered one"); return $0 > 0 })
    .reduce(0) { (total, elem) -> Int in print("counted one"); return total + 1 }
Run Code Online (Sandbox Code Playgroud)
filtered one
filtered one
filtered one
filtered one
filtered one
counted one
counted one
counted one
Run Code Online (Sandbox Code Playgroud)

使用lazy:

在这种情况下,reduce是要求一个项目计数,并将filter一直工作,直到找到一个,然后reduce将要求另一个,filter并将工作,直到找到另一个.

[1, 2, 3, -1, -2].lazy.filter({ print("filtered one"); return $0 > 0 })
    .reduce(0) { (total, elem) -> Int in print("counted one"); return total + 1 }
Run Code Online (Sandbox Code Playgroud)
filtered one
counted one
filtered one
counted one
filtered one
counted one
filtered one
filtered one
Run Code Online (Sandbox Code Playgroud)

何时使用lazy:

option- 点击进行lazy解释:

在Xcode中弹出懒惰

讨论lazy:

在链接操作时使用lazy属性:

  1. 防止中间操作分配存储

    要么

  2. 当你只需要最终集合的一部分时,以避免不必要的计算

    我想补充一点:

  3. 当您希望下游流程更快地启动而不必等待上游流程首先完成所有工作时

因此,例如,你想使用lazy之前filter,如果你正在寻找的第一个积极的Int,因为当你发现一个搜索将尽快停止,这将节省filter从有到全阵列式过滤器,它会保存有分配过滤数组的空间.

对于第3点,假设您有一个程序在该范围内1...10_000_000使用filter该范围显示素数.您宁愿在找到它们时显示素数,而不是在显示任何内容之前等待计算它们.

  • 这是一个很好的彻底答案。我有时会想到使用它的一个基本示例是当我想要数组的 '.first' 元素时。它可以潜在地节省大量工作。 (2认同)
  • 非常详细的讨论和步骤来证明惰性的使用及其背后的机制。点赞! (2认同)

Dun*_*n C 5

我之前从未见过,所以我做了一些搜索并找到了它。

您发布的语法会创建一个惰性集合。惰性集合避免为代码的每个步骤创建一系列中间数组。当您只有一个filter语句时,它并没有什么关系filter.map.map.filter.map,如果您执行类似的操作会产生更大的影响,因为如果没有惰性集合,则每个步骤都会创建一个新数组。

请参阅本文以获取更多信息:

https://medium.com/developermind/lightning-read-1-lazy-collections-in-swift-fa997564c1a3

编辑:

我做了一些基准测试,在惰性集合上,一系列的高阶函数(例如映射和过滤器)实际上要比在“常规”集合上慢一些。

看起来懒惰的集合以较小的性能降低为您提供了较小的内存占用。

编辑#2:

@discardableResult func timeTest() -> Double {
    let start = Date()
    let array = 1...1000000
    let random = array
        .map { (value) -> UInt32 in
            let random = arc4random_uniform(100)
            //print("Mapping", value, "to random val \(random)")
            return random
    }
    let result = random.lazy  //Remove the .lazy here to compare
        .filter {
            let result = $0 % 100 == 0
            //print("  Testing \($0) < 50", result)
            return result
        }
        .map { (val: UInt32) -> NSNumber in
            //print("    Mapping", val, "to NSNumber")
            return NSNumber(value: val)
        }
        .compactMap { (number) -> String? in
            //print("      Mapping", number, "to String")
            return formatter.string(from: number)
        }
        .sorted { (lhv, rhv) -> Bool in
            //print("        Sorting strings")
            return (lhv.compare(rhv, options: .numeric) == .orderedAscending)
    }

    let elapsed = Date().timeIntervalSince(start)

    print("Completed in", String(format: "%0.3f", elapsed), "seconds. count = \(result.count)")
    return elapsed
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,如果您更改行

let result = random.lazy  //Remove the .lazy here to compare
Run Code Online (Sandbox Code Playgroud)

let result = random  //Removes the .lazy here
Run Code Online (Sandbox Code Playgroud)

然后它运行得更快。对于lazy,我的基准测试显示.lazy集合的时间比直接数组要长1.5倍。

  • 如果您不需要处理整个集合,并不总是更慢。`(1...1000000).lazy.filter{ $0 % 2 == 0}.first` 使用 `lazy` 比不使用时快得多。 (3认同)