Swift 初学者交心:在 Array 和 Set 之间我们该如何抉择?

news2024/9/17 4:03:50

在这里插入图片描述

概述

初学 Swift 且头发茂密的小码农们在日常开发中必定会在数组(Array)和集合(Set)两种类型之间的选择中“摇摆不定”,这也是人之常情。

在这里插入图片描述

Array 和 Set 在某些方面“亲如兄弟”,但实际上它们之间却有着“云泥之别”。

在本篇博文中,您将学到如下内容:

  • 概述
  • 1. Array 其人
  • 2. Set 其人
  • 3. 考量运行性能
  • 4. Array 和 Set 选择原则
  • 总结

相信学完本课后,小伙伴们定能在开发中对如何选择 Array 和 Set 两种数据类型胸有成竹。

闲言少叙,Let’s make a choice!!!😉


1. Array 其人

Array 俗称数组,它其实上就是一个遵守 Collection 协议的泛型结构。在 Swift 中我们有很多种定义它的方法:

var ary0 = Array<Int>()
var ary1 = [Int]()
var ary2: [Int] = []

let ary3 = [Int](repeating: 0, count: 100)
let ary4 = [1,2,3,4,5]
let ary5 = Array((0..<100))

如上代码所示,我们还可以通过 let 和 var 关键字来调整数组的可变性。

一般来说,Swift 数组中的元素类型都是同构(或同质,homogeneous)的,这可以从它定义中只有一个泛型元素类型参数来得到印证。

在这里插入图片描述


这里不考虑使用 AnyObject 或 Any 作为数组的元素类型,也不考虑使用 Swift 5.7 之后的 any ProtocolType 来“打包存放”遵循相同协议的不同元素类型。


不过通过巧妙的利用枚举,我们可以间接的向其内部“注入”异构(heterogeneous)类型的数据:

enum MixedValue {
  case int(Int)
  case string(String)
}

let ary: [MixedValue] = [.int(1337), .string("Hello")]

如上代码所示:虽然表面上看数组 ary 中放入了 Int 和 String 两种不同类型的数据,但其实它们都是同一种 MixedValue 枚举类型。


关于更多 Swift 中枚举类型的介绍,请小伙伴们恣意观赏下面的视频课:

Swift 基本功修炼:深入浅出 Swift 中的枚举类型


Array 中元素的存放是有顺序的,无论我们遍历数组 1 千遍或是 1 万遍它们的顺序都是绝对不会变的。

除此之外,数组中的元素是可以相同的,没有哪条规定说数组不能放入一样的东西进去。这也是为什么数组定义中其元素(Element)类型是没有任何限制条件的。

Array 本身为我们提供了丰富的方法可供调用,其中最常用的一个恐怕得算是 first(where:) 方法了,它被用来在数组中查找符合条件的元素:

let ary: [Int] = [1337, 1338, 1339]

let item = ary.first(where: { $0 == 1340 })

需要注意的是:first(where:) 方法可能返回 nil 值哦。

2. Set 其人

简单聊完了数组之后,接下来我们再来看看 Set 类型。

Set 同样是一种保存同质元素的容器,我们也可以用多种方式来初始化它的实例:

let set0 = Set<Int> ([1, 2, 2, 3, 3, 4, 4, 5, 5]) 
print (set0)

var set1: Set<String> = []
set1.insert ("Hopy") 
set1.insert ("Hopy") 
set1.insert ("Panda" )
print (set1)

从上面代码来看 Set 和 Array 很相似,不过它们却有一个关键的不同:Set 中的元素必须遵守 Hashable 协议

在这里插入图片描述

这意味着:不遵循 Hashable 的类型不能放到 Set 中去,这在我们创建自定义类型时尤其需要注意。

遵循 Hashable 协议带来的另一个重要限制是:Set 中的元素必须拥有相同的 Hash 值才行。如果插入 Set 的新元素和 Set 已有元素的 Hash 值相同,则老元素会保持不动,新元素则会被无情的“拒绝”。

class Item: Hashable, Equatable {
    let value: Int
    let name: String
    
    static func ==(lhs: Item, rhs: Item) -> Bool {
        lhs.value == rhs.value
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(value)
    }
    
    init(value: Int, name: String) {
        self.value = value
        self.name = name
    }
    
    deinit {
        print("\(name) deinited!")
    }
}

var mySet = Set<Item>()

func test() {
    let item_0 = Item(value: 1, name: "hopy")
    let item_1 = Item(value: 1, name: "大熊猫侯佩")
    
    mySet.insert(item_0)
    mySet.insert(item_1)
}

test()
print(mySet.first?.name)

以上代码运行结果如下所示:

在这里插入图片描述

我们可以用 contains() 方法来检查 Set 是否包含指定的元素,我们同样可以用与数组类似的 first(where:) 方法来查找集合中符合条件的元素。

Set 和数组另一个非常重要的区别是:Set 是无序的。

当我们多次遍历同一个 Set 时即可发现:其内部元素的顺序是无法保持稳定的。

如果大家希望兼顾 Array 和 Set 两者的优点:有序且唯一,我们可以使用 Apple 官方 swift-collections package 库中的 OrderedSet 类型:

  • apple / swift-collections
    在这里插入图片描述

更多 Swift 语言中集合类型的介绍,请感兴趣的小伙伴们移步如下博文观赏进一步精彩的内容:

  • Swift 入门学习:集合(Collection)类型趣谈-上
  • Swift 入门学习:集合(Collection)类型趣谈-下

3. 考量运行性能

现在,我们已经分别简单介绍了 Swift 中的 Array 和 Set 两种类型,不过它们到底“孰是孰非”,我们还是无所适从。

接下来我们就从两者运行性能的角度来分析一番吧。

分析数组和集合性能的重要因素是它们内部元素遍历的速度。

数组元素遍历性能是 O(n),这意味着在最坏的情况下我们需要找遍数组中的所有元素才能得偿所愿,这在数组包含海量元素时会变得“蜗行牛步”。

反过来集合元素遍历性能却是 O(1),这说明要捕获 Set 内部任意元素所花费的时间都是一个“常数”,不管它们的数量是 100 个或是 1 亿个。

通过上面的讨论,我们清楚可知一点:如果我们的目的就是用最快的速度从一大堆对象里查找心仪的元素,那么 Set 是当仁不让的选择。


包含海量元素的数组在使用中往往是性能的“阿格琉斯之踵”,如果对此感兴趣的小伙伴们可以移步到以下博文中进一步学习性能优化之道:

  • 你敢信!?几行代码让Swift数组初始化提速400多倍!
  • SwiftUI一招让List巨量数据刷新UI速度快100+倍
  • 有趣简单的M2处理器性能实验:Swift与C代码执行速度的比较
  • Swift忽略大小写搜索子字符串的三种方法及性能对比

4. Array 和 Set 选择原则

综上所述,我们认为在 Set 和 Array 之间选择的最佳决策是基于实际撸码的“情境”。

当我们拥有一个哈希项目(Item)列表,这些项目在一个集合中需要是唯一的,且无需排序,这时我们倾向于使用 Set。

如果你关心秩序,或者你无法使 Item 遵守 Hashable 协议(这貌似不大可能),那么我们更应考虑使用数组。

当然,也有一个例外:即我们可能希望在维持元素顺序稳定时同时保证唯一性。在这种情况下,我们可以选择使用 swift-collections 框架中的OrderedSet(有序集合)类型。

最后一个非常重要的撸码要诀是:我们的决定总是优先基于以上原则,而不是首先考虑性能之类的东东。除非我们正在编写一段性能非常关键的代码,而在该代码中有足够的证据来证明 Set 和 Array 间的性能优劣。

记住:过早优化是万恶之源!切记!切记!


想要系统学习 Swift 语言的小伙伴们,千万不要错过我的《Swift 语言开发精讲》专栏哦,欢迎大家恣意观赏:

在这里插入图片描述

  • Swift 语言开发精讲

总结

在本篇博文中,我们简单介绍了 Swift 语言中数组(Array)和集合(Set)两种类型的特性,并比较了它们在实际运行中的性能,最后我们进一步探讨了选择它们的基本原则。

感谢观赏,再会!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1703023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于DDos防御...别在听别人瞎扯了.....

前言 无意间刷文章的时候看到一篇文章&#xff0c;写的是遇到ddos&#xff0c;怎么用iptables封IP....... 然后我就百度搜了一下&#xff0c;好多都是这么说的&#xff0c;但是我发现&#xff0c;大多数人只要遭受过长期Ddos的&#xff0c;就不会再信网上的文章 文笔不太好&…

【Qt】深入探索Qt事件处理:从基础到高级自定义:QEvent

文章目录 前言&#xff1a;1. 事件的介绍2. 事件的处理2.1. 示例1&#xff1a; 重写鼠标进入和鼠标离开事件2.2. 示例2&#xff1a;当鼠标点击时&#xff0c;获取对应的坐标值&#xff1b;2.3. 鼠标释放事件2.4. 鼠标双击事件2.5. 鼠标移动事件2.6. 鼠标滚轮的滚动事件 3. 按键…

后端经典三层架构

大家好&#xff0c;这里是教授.F 引入&#xff1a; MVC 全称∶ Model 模型、View 视图、 Controller 控制器。MVC 最早出现在 JavaEE 三层中的 Web 层&#xff0c;它可以有效的指导WEB 层的代码如何有效分离&#xff0c;单独工作。 View 视图∶只负责数据和界面的显示&#…

Python I/O操作笔记

打开文件&#xff1a; 使用 open() 函数&#xff0c;其中文件路径可以是相对路径或绝对路径。 模式除了常见的 r&#xff08;只读&#xff09;、w&#xff08;写入&#xff0c;会覆盖原有内容&#xff09;、a&#xff08;追加&#xff09;外&#xff0c;还有一些其他组合模式&…

小度推出全球首款基于文心大模型的学习机Z30,仅售价6699元

5月27日&#xff0c;小度科技召开新品发布会&#xff0c;全球首款基于文心大模型的学习机——小度学习机Z30重磅发布。 据「TMT星球」了解&#xff0c;该产品基于文心大模型&#xff0c;重新定义了“AI老师”的能力边界&#xff0c;不仅是一款能为孩子提供全面、有效学习辅导的…

LINUX环境基础练习题(附带答案)

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

嵩山为什么称为五岳之尊

在此之前&#xff0c;人们心目中的五岳之尊一般是东岳泰山。自此以后&#xff0c;观点一定会改变&#xff1a;五岳之尊是中岳嵩山&#xff01;且听我慢慢道来。 首先将二者进行一下对比—— 中与东的对比&#xff0c;嵩山居中&#xff0c;泰山居东。东方是太阳升起的地方&#…

云原生Kubernetes: 云主机部署K8S 1.30版本 单Master架构

目录 一、实验 1.环境 2.Termius连接云主机 3.网络连通性与安全机制 4.云主机部署docker 5.云主机配置linux内核路由转发与网桥过滤 6.云主机部署cri-dockerd 7.云主机部署kubelet,kubeadm,kubectl 8.kubernetes集群初始化 9.容器网络&#xff08;CNI&#xff09;部署…

牛客NC67 汉诺塔问题【中等 递归 Java/Go/PHP/C++】 lintcode 169 · 汉诺塔

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/7d6cab7d435048c4b05251bf44e9f185 https://www.lintcode.com/problem/169/ 思路 相传在古印度圣庙中&#xff0c;有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上&#xff0c;有三根杆(编号A、B、C…

书生·浦语大模型全链路开源体系-作业1

视频链接&#xff1a;书生浦语大模型全链路开源体系_哔哩哔哩_bilibili 1. LLM发展 LLM是近年来人工智能领域的一个重要发展方向。大型语言模型的历史可以追溯到2017年,当时OpenAI推出了GPT-1(Generative Pre-trained Transformer)模型,这是一个基于Transformer架构的语言生成…

论文阅读》学习了解自己:一个粗略到精细的个性化对话生成的人物感知训练框架 AAAI 2023

《论文阅读》学习了解自己&#xff1a;一个粗略到精细的个性化对话生成的人物感知训练框架 AAAI 2023 前言 简介研究现状任务定义模型架构Learning to know myselfLearning to avoid Misidentification损失函数实验结果消融实验 前言 亲身阅读感受分享&#xff0c;细节画图解释…

28【Aseprite 作图】苹果——拆解

1 画苹果框架 左边:第一行 7 第二行 2 第三 四行1 竖着7行 竖着2行 竖着1 、1 行 横着2个 横着4个 苹果可以是左右对称的,完成上述后,水平翻转到右边 2 枝叶 第一行1 左边 2 3 4 行,各1 第5行,竖着4个 再横着3个 右边 竖着3个,然后斜着2个,然后斜着1个 最上面的,两个…

RTDETR结合CVPR2024最新图像增强算法!让你的模型无惧风雨【含端到端推理脚本】

如何有效地探索雨痕的多尺度表示对于图像去雨是很重要的。与现有的基于Transformer的方法相比,这些方法主要依赖于单一尺度的雨痕外观,我们开发了一个端到端的多尺度Transformer,利用各种尺度中潜在有用的特征来促进高质量的图像重建。为了更好地探索空间变化的雨痕的常见退…

九宫格转圈圈抽奖活动,有加速,减速效果

在线访问demo和代码在底部 代码&#xff0c;复制就可以跑 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><tit…

2023idea没有VCS首次提交代码到Git

1、setting 2、vcs------>create git repository 3、右键项目----->Git------>add 4、右键项目------>git------>commit Directory 之后就会显示这个页面(下面写你提交的信息&#xff0c;就是你修改了什么) 点击commit,提交 5、Git--------->push 6、选择…

C++基础:类的继承,public,private,protected

三种继承模式 在上图中: 派生继承 三种继承模式 protected模式中 父类的公有属性和保护属性的成员在子类中都会变为保护属性,只能通过父类或者子类的成员函数调用. 代码示例: #include <iostream> #include <string> using namespace std; //protected class per…

numpy-mkl的下载地址

不要使用pip3直接在终端安装&#xff0c;因为pip3默安装的是numpy&#xff0c;而不是numpymkl。 采用在第三方库中手动下载后&#xff0c;再安装的方式。 第三方库网址&#xff1a;https://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy 如果不能进入就可以选择去git里面&#x…

代码随想录算法训练营第四十一天 | 理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

理论基础 代码随想录 视频&#xff1a;从此再也不怕动态规划了&#xff0c;动态规划解题方法论大曝光 &#xff01;| 理论基础 |力扣刷题总结| 动态规划入门_哔哩哔哩_bilibili 动归五部曲 1.dp数组以及下标的含义 2.递推公式 3.dp数组如何初始化 4.遍历顺序(例如先背包再…

Python 求积分

文章目录 Part.I IntroductionPart.II 基础知识Chap.I 特殊量的表示Chap.II integrate 函数简析 Part.III 实例Chap.I 一重积分Chap.II 二重积分 Reference Part.I Introduction 高中及大学时代&#xff0c;苦『积分』久矣&#xff0c;当时如掌握了此『黑科技』&#xff0c;课…

【MiniCPM-V】win10本地部署OCR等性能测试

性能尝试 本地配置如下 --------------------------------------------------------------------------------------- | NVIDIA-SMI 546.80 Driver Version: 546.80 CUDA Version: 12.3 | |-----------------------------------------------------…