【问题标题】:What is the difference between combining array by using reduce or joined?使用reduce或joined组合数组有什么区别?
【发布时间】:2018-07-28 18:01:37
【问题描述】:

考虑以下字符串数组:

let arrayStrings = ["H", "e", "l", "l", "o"]

为了组合它的元素(将“Hello”作为单个字符串得到),我们可以:

reduce 它:

let reducedString = arrayStrings.reduce("", { $0 + $1 }) // "Hello"

或者join它:

let joinedString = arrayStrings.joined() // "Hello"

两者都会返回“Hello”字符串作为输出。

但是,要确定什么是此类流程的更好选择,需要牢记什么逻辑?根据性能进行比较时有什么区别?

【问题讨论】:

    标签: arrays swift performance reduce


    【解决方案1】:

    joinedreduce 更好的选择有两个原因:

    1. 可读性

      如果你想将多个字符串连接成一个字符串,为什么要使用reduce,并手动连接?如果您要执行的任务有特定功能,请使用它。阅读代码时,joinedreduce 更容易理解。

    2. 性能

      joined for String 可以比reduce 更好地实现。它不一定是,但它可以。 reduce 一次操作一个元素,不知道其他元素,传递了许多临时变量。 joined 知道整个序列,并且知道操作总是相同的,因此可以优化。它甚至可以使用String的内部结构。见String.joined implementation

    总之,总是使用更具体的实现。 请注意,上述性能原因不太重要。

    【讨论】:

    • 谢谢。所以reduce 将遍历序列并为每个元素执行所有必要的过程,而joined 将整个序列视为要组合的一个块,是正确的还是我误解了它?非常感谢您的善意考虑。
    • @AhmadF reduce 遍历数组,将下一个字符串连接到上一个结果。我很确定你明白 :) 如果你查看我上面链接的String.joined 的实现,你会看到 Swift 首先遍历元素来计算结果所需的内存,然后分配(保留)内存,然后将所有字符串附加到其中。这意味着只需要一次内存分配。 reduce 必须在每一步中分配更多内存,并从上一步中释放所有内存。 joined也可以使用内部数据。
    • @AhmadF 需要注意的重要一点是,所有这些都是实现细节。相信编译器和 API 设计者,并始终使用更具体的函数版本。
    【解决方案2】:

    更新 之前的结果是在模拟器上运行 iOS 应用获得的。在真实设备上运行该应用程序,或从 MacOS 命令行应用程序运行代码与@Sulthan 提到的结果相似。


    有趣的是,reduce 在我的机器上给出了更好的结果:

    func benchmark(_ label: String, times: Int = 100000, _ f: () -> Void) {
        let start = CACurrentMediaTime()
        (0..<times).forEach { _ in f() }
        let end = CACurrentMediaTime()
        print("\(label) took \(end-start)")
    }
    
    let arrayStrings = ["H", "e", "l", "l", "o"]
    benchmark("reduce", { _ = arrayStrings.reduce("", +) } )
    benchmark("join", { _ = arrayStrings.joined() })
    

    从典型 iOS 应用的 main 方法运行时,结果大约为以下数字,在调试模式下构建:

    reduce took 0.358474982960615
    join took 0.582276367989834
    

    在发布模式下构建的相同应用程序给出了相同的结果顺序:

    reduce took 0.126910287013743
    join took 0.0291724550188519
    

    我多次运行基准测试,reduce 在所有情况下都表现得更好。不过区别并不大,所以除非你的字符串操作对性能很关键,否则我建议使用joined,该方法具有更多的语义价值,它可以更好地传达意图。

    【讨论】:

    • 您是否尝试过完全优化而不是在操场上?
    • @Sulthan 那么如果我们在具有发布模式的真实应用上试用它会不会有所不同?
    • 在一个简单的控制台应用程序中,joined 的结果始终快 4 倍。 Playgrounds 不适合性能测试,您无法在调试模式下检查性能(禁用编译器优化)。当然,我们也应该使用更长的数组和更长的字符串进行测试,但这是另一个问题。
    • 请注意,在 playground 上多次运行此代码会产生不同的结果。
    • @Sulthan 我将代码作为单元测试包的一部分运行,调试模式。不过,不确定在优化的二进制文件中运行代码是否会产生不同的结果,因为我们调用的方法是同一个 Swift 二进制文件的一部分。
    猜你喜欢
    • 1970-01-01
    • 2021-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    相关资源
    最近更新 更多