欢迎阅读有关 Swift 中高阶函数的系列文章的第四篇。今天我将展示更多可在 Swift 中使用的这些函数,它们和其他所有函数一样,可以真正帮助我们编写更简洁、更短的代码。
在深入探讨这篇文章的主要内容之前,先总结一下该系列之前的文章:
在菜单上今天是reduce,contains,allSatisfy和removeAll高阶函数。让我们一一浏览它们。
减少高阶函数
的reduce高阶函数具有简单的目的; 根据我们提供给它的计算,从集合的元素中生成单个值。
让我们通过一个简单的例子来看看这意味着什么以及它是如何工作的。假设我们有以下数组,其中包含一周内每天的平均温度(以摄氏度为单位):
let temperatures = [15, 17.3, 16.4, 18.1, 17.9, 16.5, 17.1]
在一周结束时,我们要计算所有天的平均温度。为此,有必要获得所有温度的总和,然后除以天数 (7)。执行该计算的自定义实现如下所示:
var sum: Double = 0
for temp in temperatures {
sum += temp
}
let avg = sum / 7
虽然这并没有错,但我们可以使用reduce高阶函数做得更好,最终只能在线,而不是我们这里有五个。
让我们先看看reduce它的扩展形式:
let avg = temperatures.reduce(0) { (prevResult, currentTemp) -> Double in
prevResult + currentTemp
} / 7
像任何其他高阶函数一样,reduce可以通过集合对象访问;这就是temperatures这里的数组。看到返回的结果除以 7 以计算适当的平均温度。
reduce接受两个参数;第一个是计算开始的*初始值,*你可以把它想象成sum上面( sum = 0)值的初始化。
第二个参数也是一个带有两个参数的闭包。第一个是每次迭代计算的部分结果,第二个是集合中当前项的值。
我们可以使用简写参数代替在闭包中使用实际参数并具有返回类型,并缩短上面的代码。我们这样做:
let avg = temperatures.reduce(0, { $0 + $1 }) / 7
该$0参数是在每次迭代的部分结果,并且$1是在当前的项目temperatures将被加入到部分和阵列。
看到只用一行就可以实现我们在原始实现中用五行实现的效果。但是reduce当我们有基本的计算时会变得更简单,就像这个例子中的那样。我们可以用我们想要执行的操作的符号替换包含计算公式的闭包:
let avg = temperatures.reduce(0, +) / 7
非常简单,对吧?
我们也可以reduce与字典一起使用,几乎就像我们将它们与数组一起使用一样。再次考虑温度,但这次我们将它们作为日期名称旁边的值放入字典中:
let dayTemps = ["Monday": 15, "Tuesday": 17.3, "Wednesday": 16.4,
"Thursday": 18.1, "Friday": 17.9,
"Saturday": 16.5, "Sunday": 17.1]
计算一周的平均温度类似于我们之前已经遇到的$0和$1参数。此时唯一的区别是,我们需要明确的访问value中的$1说法,因为$1是自己的一个元组,其中包含每个键-值对。在代码中:
let avgTemp = dayTemps.reduce(0, { $0 + $1.value }) / 7
这就是reduce高阶函数的全部内容。它很容易使用,最重要的事情可能是您将为它提供的初始值。
包含高阶函数
该contains高阶功能可以很容易地确定一个集合的项目满足给定条件或没有,返回一个布尔值作为结果。
contains是一个非常方便的函数,因为根据应用于集合元素的某些条件的结果,通常需要为程序的执行提供不同的路径。要查看它是如何工作的,假设以下数组包含应用程序已翻译成的所有语言:
let languages = ["English", "French", "Spanish", "Greek", "Chinese", "Turkish"]
现在假设我们要检查集合中是否存在某种语言。为了这个例子,假设我们正在寻找德语的存在。这种情况下的条件是检查是否有任何数组项等于“German”值。
让我们首先看看我们将如何使用for-in循环执行该检查:
var germanExists = false
for language in languages {
if language == "German" {
germanExists = true
break
}
}
简单,但对于这样一个简单的任务来说太多的行了。现在让我们看看我们将如何对contains函数执行相同的操作:
let germanExists = languages.contains { language -> Bool in
return language == "German"
}
函数的闭包有一个参数代表原始集合中的每一项。请注意,它的返回值始终是布尔值。闭包的主体是编写我们要确定是否有任何项目满足的自定义条件的地方。
与所有高阶函数一样,contains也有一个较短的版本:
let germanExists = languages.contains { $0 == "German" }
$0速记参数再次取代显式参数名称并使整个语法更短更清晰。大括号之间唯一需要的是条件。
现在让我们通过另一个示例,为此我们将使用带有上一部分温度的字典。假设我们要检查是否至少有一天的温度低于 10 度。有了contains这容易,如下图所示:
let lowTemp = dayTemps.contains { $0.value < 10 }
或者,我们可以检查是否有温度超过 17 度的日子:
let highTemp = dayTemps.contains { $0.value > 17 }
再次注意以上所有返回一个真值或假值;不是满足条件的实际项目。如果您想获得实际项目,那么您应该使用[filter](https://serialcoder.dev/ios-swift-tutorials/higher-order-functions-in-swift-foreach-filter-sorted/)高阶函数。
allSatisfy 高阶函数
类似的contains是allSatisfy高阶函数。它的工作原理与前一个完全一样,结果返回一个布尔值。然而,有很大的不同;*如果只有集合中的所有项目都满足给定条件,则返回 true,否则返回 false。*这与 相反contains,如果集合中至少有一项满足条件,则返回 true。
假设以下数组包含一个学生在五节课中的成绩作为百分比值 (0 – 100):
let grades = [85, 74, 90, 64, 82]
示例场景是确定学生是否将基础传递给所有课程,这意味着每个成绩都超过 50%。我们可以使用allSatisfy函数来实现:
let pass = grades.allSatisfy { grade -> Bool in
return grade > 50
}
在迭代原始数组时,闭包的参数与原始数组上的每个等级相匹配。与 类似contains,返回值始终是一个布尔值,而闭包的主体是写入条件的地方。
上面的简短版本是这样的:
let pass = grades.allSatisfy { $0 > 50 }
allSatisfy对 来说同样方便和有用contains,只需记住它们的区别并在必要时使用它。
removeAll 高阶函数
在removeAll当你想高阶功能是非常有用的基于给定条件的集合中删除的项目。它并不意味着像remove(at:)方法那样用于删除特定位置的元素。相反,它的目的是只删除那些满足条件的元素。
有两点需要注意removeAll。第一个是它不返回新集合,而是修改原始集合。请记住,如果保留源代码集合对您的程序很重要。第二个是removeAll仅适用于数组,不适用于字典或集合。
要了解如何使用它,让我们考虑grades上一部分中的数组,但有一个区别;我们用var关键字标记它,以便它可以变异:
var grades = [85, 74, 90, 64, 82]
假设我们要删除所有小于 75 的项目,因此我们只保留高于该分数的那些分数。使用removeAll扩展形式的函数,我们可以这样做:
grades.removeAll { grade -> Bool in
return grade < 75
}
请注意,要删除的项目应满足条件,而不是应保留在数组中的项目。
就像前面介绍的最后两个高阶函数一样,闭包的主体是编写自定义条件的地方。以上可以写得更短:
grades.removeAll { $0 < 75 }
grades在上述之后打印数组将为我们提供:
[85, 90, 82]
如您所见,使用该removeAll函数与之前演示的其他高阶函数一样容易。这是一个非常有用的工具,当需要执行与其目的相匹配的任务时,它可以使我们免于不必要的编码。
概括
在这篇文章中,我介绍并讨论了 Swift 中的另一组高阶函数。与之前文章中的所有其他函数一样,这些是了解和使用的好工具,因为它们可以使代码更短、更清晰、更易读和可维护。我希望你今天从这篇文章的内容中找到了有价值的信息。感谢您的阅读!
- 底层相关的面试文章(github.com/iOS-Mayday/…
- 简历指导和常见算法(github.com/iOS-Mayday/…