在上一篇 文章中, 我介绍了 Swift 中的高阶函数,解释了这种函数是什么以及如何创建自己的函数。在这篇文章中,我将专注于 Swift 中捆绑的一些特定的高阶函数,我也会在下一篇文章中继续这样做。
今天我将重点介绍三个高阶函数。人们可以看出他们属于同一个家庭;然而,它们有一定的差异,每个都用于特定的目的和用例。这些都是
map
,
compactMap
和
flatMap
高阶函数。
强调 所有 map 函数都适用于集合 是非常重要和必要的;数组、字典和集合。然而,看到它们更频繁地与数组一起使用是很常见的,因为这是编码时最常用的集合类型。
映射高阶函数
map
高阶函数的目的是*遍历集合的所有元素,对每个元素进行操作,并返回一个带有结果的新集合。*换句话说,它获取一个集合作为输入,用它做一些事情,然后返回另一个集合。
此外,
map
与任何其他高阶函数一样,函数可以帮助我们编写更短、更清晰的代码。发生这种情况是因为使用一行代码,我们可以用自定义实现替换一堆行,这些实现将对集合执行完全相同的操作。
以下示例将有助于清除所有这些。要查看所有操作,只需在 Xcode 中打开一个操场并使用您将在此过程中遇到的代码。
让我们从以下数组开始;它包含十个随机国家的名称:
let countries = ["France", "Germany", "United States of America", "United Kingdom", "Australia", "Greece", "Italy", "Spain", "Canada", "Egypt"]
为了这个例子,假设我们想提出一个新数组,其中每个项目将显示每个国家/地区名称的长度。让我们首先使用自定义实现,而不使用任何高阶函数:
var namesLength = [Int]()
for i in 0..<countries.count {
let totalChars = countries[i].count
namesLength(totalChars)
第一步是初始化一个新数组(namesLength
上面调用)。然后,在一个for-in
循环中,我们获取每个名称字符串的长度,然后将其附加到新数组中。
现在让我们使用map
高阶函数。为此,我们使用原始集合中的点语法访问它。它接受一个方法或一个闭包作为参数,在它的主体内部实现了自定义逻辑。在这里,我们将返回每个国家/地区名称的长度。最常见的方法是使用闭包,并按照 Xcode 的自动建议自动附加闭包的主体:
namesLength = countries.map { (country) -> Int in
return country.count
闭包中的参数值表示countries
数组中的每个国家/地区名称。还有一个返回值;在这个例子中,我们想要返回一个整数,显示每个国家名称的长度。
上面的实现肯定比自定义的要短,但是通过省略返回类型和return
闭包体内的关键字,它可以变得更短:
namesLength = countries.map { country in
country.count
即使不再显式指定返回类型,它也会根据闭包主体中的任何计算或操作产生的返回值自动推断。
上面可以变得更短更简单,这次我们将省略参数值。相反,我们将使用速记参数:
namesLength = countries.map {
$0.count
当然,我们可以只在一行中写上上面的内容:
namesLength = countries.map { $0.count }
我们不仅用一行替换了原来的五行代码,而且与最初的实现相比,上面的语句要简洁得多。map
函数创建一个新数组,在每个位置附加相应国家/地区名称的长度,同时countries
在幕后遍历数组中的所有名称。
以上所有代码片段都是等价的,它们返回以下数组:
[6, 7, 24, 14, 9, 6, 5, 5, 6, 9]
这是使用该map
函数的另一个示例。它将所有国家/地区名称转换为大写,并将它们附加到一个新数组中:
let uppercasedCountries = countries.map { $0.uppercased() }
print(uppercasedCountries)
打印的数组如下:
["FRANCE", "GERMANY", "UNITED STATES OF AMERICA", "UNITED KINGDOM", "AUSTRALIA", "GREECE", "ITALY", "SPAIN", "CANADA", "EGYPT"]
map
使用字典时,高阶函数也非常有用。它最大的优点之一是它可以很容易地分离键和值,从而获得包含一个或另一个的两个不同的数组。
让我们以下面的字典为例,它包含前面例子中的国家和它们所属的大陆:
var countriesAndContinents = ["France": "Europe", "Germany": "Europe", "United States of America": "America", "United Kingdom": "Europe", "Australia": "Australia", "Greece": "Europe", "Italy": "Europe", "Spain": "Europe", "Canada": "America", "Egypt": "Africa"]
以下两行返回两个不同数组中的键和值:
let keys = countriesAndContinents.map { $0.key }
let values = countriesAndContinents.map { $0.value }
但是map
的用处并不止于此;在修改键或值后,我们可以轻松地获得一个新字典,并使用map
.
为了展示这一点,假设我们想创建一个新字典,其中包含所有大写的值(本例中的大洲)。显然,以下内容是不正确的,因为它返回一个仅包含所有值的数组:
let results = countriesAndContinents.map { $0.value.uppercased() }
实际工作的技巧如下:
let results = countriesAndContinents.map { ($0.key, $0.value.uppercased()) }
看到从的闭包返回了一个元组map
。第一个值是每个键,第二个是每个大写的值。results
数组是一个元组数组,它是有目的的。我们可以通过将它作为参数提供给 Dictionary 类型的特定初始化器来使用它,因此最终得到一个新字典:
let updatedCountriesAndContinents = Dictionary(uniqueKeysWithValues: results)
打印updatedCountriesAndContinents
将显示:
["United States of America": "AMERICA", "Spain": "EUROPE", "Canada": "AMERICA", "Egypt": "AFRICA", "Italy": "EUROPE", "United Kingdom": "EUROPE", "Germany": "EUROPE", "Australia": "AUSTRALIA", "Greece": "EUROPE", "France": "EUROPE"]
compactMap 高阶函数
如果您知道如何map
工作,那么您可以以类似的方式使用这两者compactMap
以及flatMap
您接下来将阅读的函数。
compactMap
完全一样,map
但有一个很大的不同;如果它们存在于原始集合中,它会忽略任何 nil 值。
让我们countries
再次以数组为例,只是这次 nil 值替换了一些实际的国家/地区名称:
let countriesWithNil = ["France", nil, "United States of America", nil, "Australia", "Greece", nil, "Spain", nil, "Egypt"]
为简单起见,让我们再次假设我们希望国家名称大写。使用map
,我们需要有选择地解开map
的参数:
let uppercased = countriesWithNil.map { $0?.uppercased() }
结果数组将包含以下可选值和 nil 值:
[Optional("FRANCE"), nil, Optional("UNITED STATES OF AMERICA"), nil, Optional("AUSTRALIA"), Optional("GREECE"), nil, Optional("SPAIN"), nil, Optional("EGYPT")]
这有时可能适合您,但如果您想获得原始数组中具有实际名称的国家/地区的结果,那么compactMap
您真正需要使用的是:
let uppercased = countriesWithNil.compactMap { $0?.uppercased() }
这次生成的数组不包含任何选项,并且省略了 nil 值:
["FRANCE", "UNITED STATES OF AMERICA", "AUSTRALIA", "GREECE", "SPAIN", "EGYPT"]
知道现在compactMap
做了什么,使用它而不是map
当你想摆脱 nil 值时,或者只是在原始集合中忽略它们。除此之外,有关该map
功能的所有其他讨论也适用于此。
flatMap 高阶函数
当您需要*从彼此包含的其他集合中获取单个集合时,*此高阶函数非常方便。为了澄清这一点,假设以下数组保持一个城市在早上和下午的平均温度(以摄氏度为单位):
let temps = [15, 18]
现在假设我们有七个类似上面的数组到另一个数组中,匹配一周中的 7 天:
let weekTemps = [[15, 18], [17.5, 16], [13.4, 14.1], [14.4, 15.2], [15, 15.8], [16.8, 17.9], [16, 18.2]]
现在,如果我们想计算整周的平均温度怎么办?如果我们可以将所有温度都存在于单个阵列中,那将非常方便。
这就是flatMap
它的作用;它将嵌套集合中的值合并为一个单一的集合。实现这一目标所需的一切如下:
let allTemps = weekTemps.flatMap { $0 }
所有温度现在都存在于一个数组中:
[15.0, 18.0, 17.5, 16.0, 13.4, 14.1, 14.4, 15.2, 15.0, 15.8, 16.8, 17.9, 16.0, 18.2]
上述转换使得处理这些值并使用它们做一些事情变得更加容易。
在上一篇对高阶函数的初步介绍之后,这里我简要介绍了如何使用 Swift 中提供的一些常见和相似的高阶函数,解释它们的用途、工作原理以及它们如何帮助编写更好的代码. 他们中的更多人将来到下一个帖子,所以不要错过它。感谢您的阅读时间!
底层相关的面试文章(github.com/iOS-Mayday/…
简历指导和常见算法(github.com/iOS-Mayday/…
快手电商无线团队