Swift 中 Set 和 Array 的对比

前言

数组(Array) 和 集合(Set) 在一开始看起来似乎非常相似。它们都是集合类型,并且有很多共同之处。不过,在实际开发场景中,我们常常倾向于使用数组而非集合。虽然这不一定是个问题,但有时选择集合可能是一个更好的选择。

基础概念的区别

在探讨选择数组(Array)还是集合(Set)的实际原因之前,我们先来了解一下这两种类型在使用上的几个基本差异。

初始化方式

当我们对比数组和集合的初始化过程时,可以发现它们实际上是非常相似的。示例代码如下:

vbnet 复制代码
let array: [String] = ["Swift", "Objective-C", "Xcode", "Java", "C++"]
let set: Set<String> = ["Swift", "Objective-C", "Xcode", "Java", "C++"]

这两种类型都支持相同的 ExpressibleByArrayLiteral 协议,不过了解一下"数组字面量"类型默认就是数组这一点也是很有帮助的。也就是说,如果是相同的集合类型字符串字面量,不显式的指定类型的话默认就是数组类型。比如下面的代码:

c 复制代码
let array = ["Swift", "Objective-C", "Xcode", "Java", "C++"] // Array<String>

起初,你可能会认为这两个集合在初始化后是完全相同的。然而,实际情况并非如此。下面是来自官方文档的描述:

scala 复制代码
A set stores distinct values of the same type in a collection with no defined ordering. You can use a set instead of an array when the order of items is not important, or when you need to ensure that an item only appears once.

从这段文档中我们可以看出 Set 的与 Array 的两点非常重要的区别:

  • Set 存储的元素是无序的。
  • Set 存储的每个元素都是唯一的,没有重复的元素。

比如下面这段代码:

vbnet 复制代码
let set: Set<String> = ["Swift", "Objective-C", "Xcode", "Java", "C++", "Swift"] // ["Java", "C++", "Swift", "Xcode", "Objective-C"]

可以看到,虽然 set 里面存储了两个字面量为 Swift 的字符串,但打印中只包含一个,且打印的顺序和赋值的顺序并不一致。

在选择使用 Array 还是 Set 时,上述两点是非常重要,一定要考虑到。

添加元素

Array 和 Set 都是值类型。因此,如果使用 let 关键字将它们定义为常量,那么在尝试添加元素时就会出现以下错误:

c 复制代码
array.append("JS") // Cannot use mutating member on immutable value: 'array' is a 'let' constant
set.insert("JS") // Cannot use mutating member on immutable value: 'array' is a 'let' constant

如上述代码中所见,我们在此处发现了第一个不同之处。对于数组,我们需要使用 append(_:) 方法来添加元素,而对于 Set,则需要使用 insert(_:) 方法。这两种方法都会将 JS 字符串添加到集合中,但仅在数组中,我们确切地知道它已被添加到末尾,因为数组是有序排列的。

这里还有一个不同之处在于 insert(_:) 方法的返回类型。它会返回一个布尔值(表示插入是否成功)以及一个 memberAfterInsert 属性,该属性要么包含已存在的对象,要么包含刚刚插入的对象。如果想要向用户反馈某个对象是否已存在,这一点会很有用:

swift 复制代码
let result = set.insert("Swift")
if !result.inserted {
    print("\(result.memberAfterInsert) 已存在")
}

元素的唯一性

集合(Set)和数组(Array)之间的一个重要区别在于元素的唯一性。数组可以包含相同的值两次以及多次,而集合则绝不会出现重复元素。这也是上述的 insert(_:) 方法返回一个布尔值以表明插入操作是否真正成功的根本原因。

这是一个重要的区别,它可能是选择使用集合而非在数组上使用过滤器来剔除重复项的原因。

元素的有序

数组和集合之间的第二个区别在于元素的排列顺序。相关文档也有这样的描述:

  • 数组:一种有序的、可随机访问的集合。
  • 集合:一个不含重复元素的无序集合。

因此,如果你的使用场景需要考虑元素的顺序,那么应该选择使用数组。

性能差异

选择使用集合的另一个原因在于:当性能至关重要时,或者当需要处理大量数据时。集合中的元素必须符合 Hashable协议,这使得集合在性能方面具有优势。在小型集合和大型集合中查找元素所花费的时间是相同的。

一般来说,如果可能的话,创建不可变的集合对于提高性能来说是很有好处的。这适用于数组和集合这两种数据结构,并且能让 Swift 编译器优化创建的集合的性能。

总结

若需要元素有序,且可以存储重复元素选择 Array;若不需要元素有序,且元素值要唯一选择 Set。

相关推荐
光影少年14 小时前
React 组件中怎么做事件代理?它的原理是什么?
前端·react.js·掘金·金石计划
瓜子三百克21 小时前
值类型大小与内存分配
swift·内存分配
杂雾无尘2 天前
Swift 5.9 新特性揭秘:非复制类型的安全与高效
ios·swift·apple
Daniel_Coder3 天前
iOS Widget 开发-7:TimelineProvider 机制全解析:构建未来时间线
ios·swift·widget
Swift社区3 天前
Swift 图论实战:DFS 算法解锁 LeetCode 323 连通分量个数
算法·swift·图论
Daniel_Coder3 天前
iOS Widget 开发-3:Widget 的种类与尺寸(主屏、锁屏、灵动岛)
ios·swift·widget
大熊猫侯佩3 天前
Swift 6.2:江湖再掀惊涛浪,新功出世震四方
swift·apple·wwdc
大熊猫侯佩3 天前
WWDC 25 风云再起:SwiftUI 7 Charts 心法从 2D 到 3D 的华丽蜕变
swiftui·swift·wwdc
杂雾无尘3 天前
SwiftUI 新手必读:如何用纯 SwiftUI 在应用中实现分段控制?
ios·swift·apple
开发者如是说4 天前
言叶是如何对文件进行端到端加密的
android·kotlin·swift