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

在这里插入图片描述

概览

集合的概念在任何编程语言中都占有重要的位置,正所谓:“古来聚散地,宿昔长荆棘;游人聚散中,一片湖光里”。把那一片片、一瓣瓣、一粒粒“可耐”的小精灵全部收拢、吸纳的井然有序、条条有理,怎能不让我们满心欢喜呢?

在这里插入图片描述

在这里,我们就和 Swift 语言刚入门的小伙伴们一起来闲聊一番关于集合有趣的内容吧。

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

  • 概览
  • 1. 数据总动员:集合!
  • 2. 数组
  • 3. 字典
  • 总结

在下篇中,我们将继续介绍更多的集合类型,以及其它集合类型有趣的扩展知识。

Swift 中集合的概念简约却不简单,那还等什么呢?

Let’s collect it now!!!😉


1. 数据总动员:集合!

Swift 语言以其独有的简洁、安全、现代化等特性迅速吸引着众多已秃和还未秃的小码农们!在 Swift 语言标准库中包含了 3 种“著名”的集合类型(Collection Types),它们分别是:Array、Dictionary 和 Set。

在这里插入图片描述

在 Swift 中之所以认为它们是集合类型,是因为它们都遵守了 Collection 协议:
在这里插入图片描述

而 Collection 又遵守着 Sequence 协议,环环相套、生生不息。

在 Swift 语言中,集合的本质是容器,里面存放着有序或无序的元素。而遵守 Collection 协议的一大好处是只需实现简单几个属性和方法,我们即可免费获得全套海量通用的集合操作,比如:map()、randomElement()、prefix() 方法等等。

其中,一些方法实际是否适用还要看集合元素的“脸色”,比如下面这些方法就要求方法元素类型遵守 Equatable 协议:

func contains<C>(C) -> Bool
func firstIndex(of: Self.Element) -> Self.Index?
func split(separator: Self.Element, maxSplits: Int, omittingEmptySubsequences: Bool) -> [Self.SubSequence]

其实,小伙伴们可能不知道的是:如果遵守 Collection 协议的类型都算集合,恐怕在 Swift 中符合条件的类型得有一个“加强连”:

遵守 Collection 的类型:AnyBidirectionalCollection
AnyCollection
AnyRandomAccessCollection
AnyRegexOutput
Array
ArraySlice
ClosedRange
Conforms when Bound conforms to Strideable and Bound.Stride conforms to SignedInteger.
CollectionDifference
CollectionOfOne
ContiguousArray
DefaultIndices
Conforms when Elements conforms to BidirectionalCollection.
Dictionary
Conforms when Key conforms to Hashable.
Dictionary.Keys
Conforms when Key conforms to Hashable.
Dictionary.Values
Conforms when Key conforms to Hashable.
EmptyCollection
FlattenSequence
Conforms when Base conforms to BidirectionalCollection and Base.Element conforms to BidirectionalCollection.
Int.Words
Int16.Words
Int32.Words
Int64.Words
Int8.Words
KeyValuePairs
LazyDropWhileSequence
Conforms when Base conforms to Collection.
LazyFilterSequence
Conforms when Base conforms to BidirectionalCollection.
LazyMapSequence
Conforms when Base conforms to RandomAccessCollection.
LazyPrefixWhileSequence
Conforms when Base conforms to BidirectionalCollection.
LazySequence
Conforms when Base conforms to RandomAccessCollection.
Range
Conforms when Bound conforms to Strideable and Bound.Stride conforms to SignedInteger.
Repeated
ReversedCollection
Conforms when Base conforms to RandomAccessCollection.
Set
Conforms when Element conforms to Hashable.
Slice
Conforms when Base conforms to RandomAccessCollection.
String
String.UTF16View
String.UTF8View
String.UnicodeScalarView
Substring
Substring.UTF16View
Substring.UTF8View
Substring.UnicodeScalarView
UInt.Words
UInt16.Words
UInt32.Words
UInt64.Words
UInt8.Words
Unicode.Scalar.UTF16View
Unicode.Scalar.UTF8View
UnsafeBufferPointer
UnsafeMutableBufferPointer
UnsafeMutableRawBufferPointer
UnsafeRawBufferPointer

这里列这么一大坨实在不是想吓跑各位天真的小伙伴们,只是单纯的想列出来而已~ 😦

除了最常用的 Array、Set 和 Dictionary 三个集合类型之外,我们还将介绍一个有趣的 Range 类型,使用它我们可以描述无限的大集合。


如果觉得上面这些集合类型“一个都不能打”,我们也可以自行动手创建自定义集合类型,你猜对了:就是遵守 Collection 协议即可!

由于篇幅所限,创建自定义集合的话题不在本文范围之内,有缘会在随后的博文中与大家相见。


2. 数组

数组(Array)是很常见的集合类型:

在这里插入图片描述

在 Swift 中数组其实就是一个遵守 Collection 协议的泛型结构。我们可以用多种方法来创建数组:

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))

如上,我们变着花似地创建了 6 个整数(Int)数组,其中前三个是可变数组,后三个是不可变数组,或者称为只读数组。

我们可以在创建时为数组赋值,或者随后再动态插入新的元素:

var ary = [Int]()
for i in 0..<100{ary.append(i*i)
}

如果可能,还是尽量在数组创建时就“填满它”,这样会更具效率。而且在数组尾部新增元素比头部会快更多!

更多数组性能的优化秘技请大家参考如下链接:

  • 你敢信!?几行代码让Swift数组初始化提速400多倍!
  • SwiftUI一招让List巨量数据刷新UI速度快100+倍

我们可以在数组上应用多种方法:

let ary = Array((0..<100))
// 整数数组元素求和
let total = ary.reduce(0) { $0 + $1 }
// 将整数数组转换为字符串数组
let stringAry = ary.map {String($0)}let neg_ary = -100..<0
// 组合两个数组
let zip_ary = zip(ary, neg_ary).map {[$0*$0, $1]}

因为在 Swift 语言中,数组被实现为结构而非类,由于结构的值拷贝特质:copy 后的数组和原数组就“再无瓜葛了,我们可以随心所欲的改变它而不影响前者:

var ary0 = [1,2,3]
var ary1 = ary0
ary1[0] = -1print([ary0, ary1])
// 输出: [[1, 2, 3], [-1, 2, 3]]

不过,上面说的这种 copy 又称之为“浅拷贝”,这意味着如果数组元素为引用类型,那么它们的改变仍然会影响新旧两个数组,使用时请尤其留意:

在这里插入图片描述

在上面的代码中,我们改变了新数组中第一个元素的内容,原数组的对应元素也发生了改变。这是因为其元素的类型是 NSMutableString,它是一个引用类型。数组浅拷贝只是 copy 它们的引用,所以实际上它们的改变“所有人都逃不了干系”。

除了普通的数组以外,还存在一种“奇懒无比”的惰性数组:LazySequence。

在这里插入图片描述

其实它应该被称为“惰性序列”,因为它更像一种序列(Sequence)。其包含的每个元素都只在需要时才会被求值,我们会在随后介绍 Range 类型时对 LazySequence 做更进一步的说明。

3. 字典

聊完了数组之后,我们再来与字典(Dictionary)打声招呼吧:

在这里插入图片描述

字典是描述键值(Key-Value)对应关系的一种集合容器。从上面字典的定义中可以看到其键类型必须遵守 Hashable 协议。仔细想想也是蛮有道理的:如若不然,怎么区别字典中键的唯一性呢?

如您所愿,我们同样可以用各种千姿百态的“姿势”来创建字典:

let dict0 = ["A": 0xa, "B": 0xb, "C": 0xc]
var dict1 = [String: Int]()
var dict2: [String: Int] = [:]
var dict3 = Dictionary<String,Int>()dict2["Panda"] = 11
dict2["Hopy"] = 121

与数组类似,我们可以轻松的遍历字典中的所有键和值:

let dict = ["A": 0xa, "B": 0xb, "C": 0xc]for key in dict.keys {// 单独遍历所有键
}for value in dict.values {// 单独遍历所有值
}for (key,value) in dict {// 同时遍历键和值print("\(key):\(value)")
}let total = dict.reduce("") {$0 + $1.key}

不过字典是无序的,所以不能期望遍历时它们的顺序保存稳定。实际上,依赖于字典元素间顺序的代码逻辑都是错误的,比如上面最后一行代码。

由于无法保证键一定有对应的值,所以通过字典键访问值的结果将会是一个可选类型,我们可以适时的为字典琢磨出一个默认值:

let dict = ["A": 0xa, "B": 0xb, "C": 0xc]// value 的类型为 Int?
let value = dict["A"]
// 为字典设置默认值
let concreteValue = dict["Z"] ?? 0

总结

在上篇的学习中,我们讨论了 Swift 中集合背后的 Collection 协议,并随后介绍了数组(Array)和字典(Dictionary)两种集合类型。

在下篇中,我们将继续集合大冒险,探索更多的集合类型。

感谢观赏,再会!😎

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

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

相关文章

Mac笔记本聚焦SpotLight占用内存太高的 解法

分享一个自创的绝对有效的解决苹果电脑Mac笔记本SpotLight聚焦占用内存过高的方法! 一、背景 / 问题原因 1、Mac的聚焦功能,可以快速打开应用程序,非常方便! But,随着电脑的使用文件等越来越多,就会导致SpotLight聚焦需要更多更多甚至巨多的内存来建立索引,就会导致电脑…

tcp流式服务和粘包问题

目录 1.概念 2.流式服务 3.粘包问题 1.概念 套接字是一个全双工的 使用TCP协议通信的双方必须先建立连接,然后才能开始数据的读写,双方都必须为该连接分配必要的内核资源,以管理连接的状态和连接上数据的传输. TCP连接是全双工的,即双方的数据读写可以通过一个连接进行,完成…

【C语言】linux内核ip_local_out函数

一、讲解 这个函数 __ip_local_out 是 Linux 内核网络子系统中的函数&#xff0c;部分与本地出口的 IPv4 数据包发送相关。下面讲解这段代码的每一部分&#xff1a; 1. 函数声明 int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)&#xff1a; -…

剪枝例题一道

例题一 Code force round 我的思路&#xff0c;DFS遍历所有x&#xff0c;y&#xff0c;然后用set记录所有k&#xff0c;但是TLE了&#xff0c;最后发现&#xff0c;可以应用剪枝&#xff0c;如果一个x&#xff0c;y得出的k已经在set中存在了&#xff0c;那么不用再继续DFS后续…

react实战——react旅游网

慕课网react实战 搭建项目问题1.按照官网在index.tsx中引入antd出错&#xff1f;2.typescript中如何使用react-router3.react-router3.1 V63.2 V53.3V6实现私有路由 4.函数式组件接收props参数时定义数据接口&#xff1f;5.使用TypeScript开发react项目&#xff1a;6.要使一个组…

SQLite3中的callback回调函数注意的细节

调用 sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void *data, char **errmsg)该例程提供了一个执行 SQL 命令的快捷方式&#xff0c; SQL 命令由 sql 参数提供&#xff0c;可以由多个 SQL 命令组成。 在这里&#xff0c; 第一个参数 sqlite3 是打开的数据库对…

代码随想录算法训练营第day41|背包理论基础、416. 分割等和子集

目录 a.背包理论基础——01背包 1.二维数组的01背包表示 2.一维滚动数组表示 b. 416. 分割等和子集 - 力扣&#xff08;LeetCode&#xff09; a.背包理论基础——01背包 背包问题分类&#xff1a; 对于面试的话&#xff0c;其实掌握01背包&#xff0c;和完全背包&#xff…

Excel F4键的作用

目录 一. 单元格相对/绝对引用转换二. 重复上一步操作 一. 单元格相对/绝对引用转换 ⏹ 使用F4键 如下图所示&#xff0c;B1单元格引用了A1单元格的内容。此时是使用相对引用&#xff0c;可以按下键盘上的F4键进行相对引用和绝对引用的转换。 二. 重复上一步操作 ⏹添加或删除…

SSM框架,MyBatis-Plus的学习(下)

条件构造器 使用MyBatis-Plus的条件构造器&#xff0c;可以构建灵活高效的查询条件&#xff0c;可以通过链式调用来组合多个条件。 条件构造器的继承结构 Wrapper &#xff1a; 条件构造抽象类&#xff0c;最顶端父类 AbstractWrapper &#xff1a; 用于查询条件封装&#xf…

首屏性能优化:提升用户体验的秘籍

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

复盘-excel

excel-选列没有用&#xff0c;选小标题才可以 将簇状柱形图放置在一个新表上##### excel: 添加数据模型时&#xff0c;要通过套用表格格式与外部断开连接 透视分析2010年人数未解决(第四套&#xff09; 通过日期显示星期几 判断星期几 因为前面已经通过星期六&#xff0c…

03_Tomcat

文章目录 Tomcat概念自制简易的服务器JavaEE规范Tomcat安装Tomcat启动Tomcat的资源部署直接部署虚拟映射 Tomcat的设置 Tomcat 概念 服务器&#xff1a;两层含义。 软件层面&#xff1a;软件&#xff0c;可以将本地的资源发布到网络中&#xff0c;供网络上面的其他用户来访问…

WPF 防止按钮Click时间多次点击响应

可能不是最好的办法&#xff0c;但是用起来效果也还是可以的。 原理&#xff1a;通过IsEnabled属性来控制按钮状态。btnConfirm.IsEnabled / this.IsEndbled 这两种方式是等价的。 案例比较简单&#xff0c;如果后期做开发的话代码量变大&#xff0c;只在结尾添加 this.IsEn…

网络综合布线

综合布线的英文表达为Structured Cabling System&#xff08;通俗表达为Cabling System&#xff0c;简称CSC&#xff0c;最早由AT&T提出&#xff09;或Premises Distribution System&#xff08;PDS&#xff0c;目前国标采用这一称法&#xff09;。   综合布线起源与发展…

Druid数据库连接池配置

客户端DruidDataSource 配置项描述建议值maxWait从连接池中获取connetion的最长等待时间10s TimeBetweenEvictionRunsMillis 轮询检查数据库连接池状态的间隔60s MinEvictableIdleTimeMillis 躺在连接池没有干活的空闲状态的最小值300s MaxEvictableIdleTimeMillis 1.躺在连接…

grafana table合并查询

注&#xff1a;本文基于Grafana v9.2.8编写 1 问题 默认情况下table展示的是一个查询返回的多个field&#xff0c;但是我想要的数据在不同的metric上&#xff0c;比如我需要显示某个pod的读写IO&#xff0c;但是读和写这两个指标存在于两个不同的metirc&#xff0c;需要分别查…

LeetCode27: 移除元素

题目描述 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出…

【DevOps基础篇】容器化架构基础设施监控方案

【DevOps基础篇】容器化架构基础设施监控方案 目录 【DevOps基础篇】容器化架构基础设施监控方案要监视什么不同监控系统方案比较1. Datadog2. Prometheus3. ELK(Elasticsearch、Logstash、Kibana)4. Sysdig5. 自行打造!如何选择总结推荐超级课程: Docker快速入门到精通 当…

Android谈谈ArrayList和LinkedList的区别?

Android中的ArrayList和LinkedList都是Java集合框架中的List接口的实现&#xff0c;但它们在内部数据结构和性能特性上有所不同&#xff1a; 1. **内部数据结构**&#xff1a; - ArrayList是基于动态数组&#xff08;可调整大小的数组&#xff09;实现的。它在内存中是连续…

ActivityRecord中Activity生命周期变化

本文基于AOSP13分析 ActivityRecord一些关键的属性&#xff1a; final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {// pause 超时时间private static final int PAUSE_TIMEOUT 500;// stop 超时时间private static fina…