前语

SwiftSequence 类型有一个强壮的操作符叫做 reduce,它允许你将序列的一切元素组合成一个单一的值。在处理来自 App Store Connect API 的响应时,我一直在重复运用它,我觉得写一篇关于它的博客文章是个好主意。

reduce 操作符有两种不同的签名,具体代码如下:

// 运用初始成果进行 reduce
@inlinable public func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (_ partialResult: Result, Self.Element) throws -> Result) rethrows -> Result
// 将成果归并到初始成果中
@inlinable public func reduce<Result>(into initialResult: Result, _ updateAccumulatingResult: (_ partialResult: inout Result, Self.Element) throws -> ()) rethrows -> Result

这两个操作符在给定相同输入时完成相同的成果:它们从一个初始的 inout 值开端,遍历序列中的一切元素,并将它们作为参数传递给供给的闭包。因为初始值是作为 inout 参数传递的,闭包能够依据序列中的当时元素对其进行修改。每次迭代的更新值然后作为下一次迭代中闭包的第一个参数传递。

虽然它们看起来十分类似 – 它们都具有 O(n) 的复杂度,并且能够互换运用 – 但基于成果类型的不同,它们具有不同的功率影响。例如,当成果是像 ArrayDictionary 这样的写时复制类型时,你应该运用 into 变体。

运用初始成果进行 reduce

让咱们来看一个十分简单的比如,以理解 reduce 操作符的作业原理。假定你有一个整数数组,你想要核算一切元素的总和作为成果。假如你不知道 reduce 操作符,你能够写一个像这样的函数,具体代码如下:

func sumAllElements(of numbers: [Int]) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}

虽然这个函数彻底有用,但它并不是最优雅的解决方案。你能够在一行代码中运用 reduce 操作符来完成相同的成果,代码如下:

func sumAllElements(of numbers: [Int]) -> Int {
    numbers.reduce(0) { $0 + $1 }
}

或者更好的是,你能够直接将 + 操作符作为闭包传递,代码如下:

func sumAllElements(of numbers: [Int]) -> Int {
    numbers.reduce(0, +)
}

运用初始成果进行 reduce

现在让咱们来看一个稍微复杂一些的比如。假定咱们有一个 ScreenshotBundle 数组,其间每个 bundle 都有一个称号和一个指向截图的 URL 列表。咱们的 UI 需求依据用户的挑选找到具有特定称号的截图 bundle,并在图像视图中显现一切的 URL

把握 Swift 中的 reduce 操作符,使你的代码更高效

这是咱们在 Helm 中运用的代码变体,Hidde 和我正在构建 Helm,这是一款旨在使 App Store Connect 的用户更轻松、更愉快地发布运用程序和更新的运用。

咱们能够经过坚持 ScreenshotBundle 数组不变,然后搜索具有特定称号的 bundle 来完成这一点,中心代码如下:

struct ScreenshotBundle {
    let name: String
    let urls: [URL]
}
func find(bundleWithName name: String, in bundles: [ScreenshotBundle]) -> ScreenshotBundle? {
    bundles.first(where: { $0.name == name })
}

虽然这种方法可行,但它并不是最有用的。first(where:) 函数的复杂度为 O(n),你能够想象,假如数组中的元素数量很大,这可能会成为一个问题。

相反,你能够运用 reduce 操作符一次将 ScreenshotBundle 数组转换为一个字典,其间键是 bundle 的称号,值是 bundle 本身。这样,你就能够在 O(1) 的时刻复杂度内找到具有特定称号的 bundle,代码如下:

struct ScreenshotBundle {
    let name: String
    let urls: [URL]
}
func format(bundles: [ScreenshotBundle]) -> [String: ScreenshotBundle] {
    bundles.reduce(into: [String: ScreenshotBundle]()) { result, bundle in
        result[bundle.name] = bundle
    }
}
func find(bundleWithName name: String, in bundles: [String: ScreenshotBundle]) -> ScreenshotBundle? {
    bundles[name]
}

经过理解和把握 reduce 操作符,你能够更高效地处理 Swift 中的集合类型,使你的代码更加简洁和易于理解。这种强壮的操作符不仅能够提高代码的性能,还能提升开发功率,让你更轻松地应对复杂的数据处理任务。

在实际开发中,应该依据具体情况挑选适宜的 reduce 操作符,以确保代码的性能和可读性。经过合理地利用 reduce 操作符,你能够编写出更加优雅和高效的 Swift 代码,然后提升运用程序的质量和用户体会。

了解 reduce 操作符的作业原理并熟练运用它,将会使你成为一个更加出色的 Swift 开发者,为你的项目带来更大的成功和成就。

总结

本文全面介绍了 Swift 中的 reduce 操作符,这是一个强壮的东西,能够将序列的元素组合成单个值。文章解释了 reduce 操作符的两种不同签名,并经过代码示例演示了它们的用法。

其间评论了怎么运用带有初始成果的 reduce,演示了怎么以简洁而优雅的方式核算数组中元素的总和。然后,它探讨了带有初始成果的 reduce 变体,展现了怎么将数组高效地转换为字典。

本文对 Swift 开发人员来说是一份宝贵的资源,供给了关于 reduce 操作符的功能和运用的见地,使他们能够编写更高效、更优雅的代码。