Why and when to use lazy with Array in Swift?

后端 未结 2 859
野性不改
野性不改 2020-12-23 14:24
[1, 2, 3, -1, -2].filter({ $0 > 0 }).count // => 3

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

What is the advantage of ad

2条回答
  •  渐次进展
    2020-12-23 14:38

    I hadn't seen this before so I did some searching and found it.

    The syntax you post creates a lazy collection. A lazy collection avoids creating a whole series of intermediate arrays for each step of your code. It isn't that relevant when you only have a filter statement it would have much more effect if you did something like filter.map.map.filter.map, since without the lazy collection a new array is created at each step.

    See this article for more information:

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

    EDIT:

    I did some benchmarking, and a series of higher-order functions like maps and filters is actually a little slower on a lazy collection than on a "regular" collection.

    It looks like lazy collections give you a smaller memory footprint at the cost of slightly slower performance.

    Edit #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
    }
    

    In the code above, if you change the line

    let result = random.lazy  //Remove the .lazy here to compare
    

    to

    let result = random  //Removes the .lazy here
    

    Then it runs faster. With lazy, my benchmark has it take about 1.5 times longer with the .lazy collection compared to a straight array.

提交回复
热议问题