Swift 中数组合并:从 + 到 copy-on-write

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如何在 Swift 中合并数组?完整解析与性能秘诀



如果你曾经用 Swift 写过代码,很可能遇到过这样的问题:“我有两个数组,如何将它们合并成一个?”这个问题看似简单,但背后却隐藏着优化和细节的整个世界。在 Stack Overflow 上,这个问题获得了数千次浏览——这并非偶然。今天,我们不仅会展示如何编写代码,还会深入编译器底层,了解当你写下 array1 + array2 时实际发生了什么。开始吧!



最直观的方法:+ 运算符



让我们从经典方法开始。在 Swift 中,数组可以像数字一样相加:



let first = [1, 2, 3]let second = [4, 5, 6]let result = first + secondprint(result) // [1, 2, 3, 4, 5, 6]


很优雅,对吧?但并非总是很快。当你使用 + 时,Swift 会创建一个新数组,并将两个原始数组中的元素复制进去。如果你的数组很大(比如各有 10 万个元素),这对处理器来说是双倍的工作量。但等等——这里有一个叫做 copy-on-write (COW) 的细节。



Copy-on-Write 的魔法:Swift 如何节省内存



Swift 是一门聪明的语言。当你简单地将一个数组赋值给另一个数组时,它不会立即复制数据:



var a = [1, 2, 3]var b = a // 在数据被修改之前,a 和 b 指向同一块内存区域b.append(4) // 此时才发生真正的复制:b 获得自己的副本


这被称为 copy-on-write。但在通过 + 合并时,这并不适用——结果始终是一个新数组。为什么?因为我们不仅仅是引用旧数据,而是从两个不同来源的元素创建一个新的集合。编译器无法保证原始数组不会被修改,因此它会进行完整复制。



append(contentsOf:) 方法:当速度更重要时



如果你需要将一个数组的元素添加到另一个数组的末尾,而不创建第三个数组,请使用 append(contentsOf:):



var numbers = [1, 2, 3]let moreNumbers = [4, 5, 6]numbers.append(contentsOf: moreNumbers)print(numbers) // [1, 2, 3, 4, 5, 6]


在这种情况下,Swift 不会创建新数组——它只是扩展现有数组。如果 numbers 数组有足够的预留内存(capacity),新元素会直接复制到空闲位置。如果没有,则会进行内存重新分配,但这仍然比从头创建数组要快。



专业建议: 如果你知道将要添加大量元素,请使用 reserveCapacity() 预先分配内存:



var bigArray: [Int] = []bigArray.reserveCapacity(1000)for i in 0..<1000 {    bigArray.append(i) // 没有一次多余的复制!}


flatMap 方法:带转换的数组合并



有时你不仅需要连接数组,还需要对每个元素进行转换。这时 flatMap(或用于可选值的 compactMap)就派上用场了。严格来说,flatMap 用于“展平”集合,但也可以用于拼接:



let arrays = [[1, 2], [3, 4], [5, 6]]let flattened = arrays.flatMap { $0 }print(flattened) // [1, 2, 3, 4, 5, 6]


在底层,flatMap 做的事情与使用 append(contentsOf:) 的循环相同。但代码更简洁、更易读。不过,如果你只是要连接两个数组——不要使用 flatMap,那样会显得冗余。



使用 reduce(into:) 进行灵活合并



如果你有一个数组的数组,并且希望以额外的逻辑合并它们,可以尝试 reduce(into:):



let arrayOfArrays = [[1, 2], [3, 4], [5, 6]]let merged = arrayOfArrays.reduce(into: [Int]()) { r                

博客

书籍推荐