Swift 高阶函数详解(forEach、filter、map、flatMap、compactMap、reduce、sorted)

本文详细介绍了Swift中的7个高阶函数:forEach,filter,map,flatMap,compactMap,reduce,和sorted,包括它们的作用、使用方法和示例,方便开发者在实际项目中查阅和应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在学 Swift 的时候,就觉得 Swift 提供的几个高阶函数特别好用,每次有使用场景时,都会查资料看看怎么用。现在不知不觉已经写了一年多 Swift 了,这几个高阶函数也用得很熟练了,但是写文章记录这件事也因为各种工作、生活上的事情一拖再拖。

现在这篇关于高阶函数的介绍,它来了。内容主要是介绍 forEach、filter、map、flatMap、compactMap、reduce、sorted等 7 个函数的作用,以及他们的使用方式。本文可以当做字典按需查阅。

高阶函数介绍

1. forEach

forEach 函数的作用 for - in 基本一致, 它接受一个闭包参数,该闭包接受序列中的一个元素作为参数并执行某些操作。时间复杂度是 O ( n ) O(n) O(n)

函数的形式如下:

func forEach(_ body: (Element) throws -> Void) rethrows

使用例子如下:

let numberWords = ["one", "two", "three"]

// 遍历数组中的结果并打印
numberWords.forEach { word in
	print(word)
}

需要注意的是:forEach 函数没有返回值,并且不能在操作函数中改变集合中的元素

2. filter

filter 函数正如其名,它主要用于过滤数组、集合和字典等类型对象中的元素。它接受一个闭包参数,该闭包返回的结果为 true,该元素就会保留,否则就会被移除。时间复杂度是 O ( n ) O(n) O(n)

函数的形式如下:

func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> [Element]

下面是一个简单的例子,是利用 filter 函数过滤数组中的偶数,并返回一个新的数组:

let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let filteredNums = nums.filter { $0 % 2 == 0 }
print(filteredNums)  // 输出 [2, 4, 6, 8, 10]

在上面的示例中,闭包表达式 { $0 % 2 == 0 } 接受一个参数 $0,判断 $0 是否为偶数,如果是则返回 true,否则返回 false。

3. map

map() 函数用于对集合中的每个元素进行转换,并返回一个新的集合,其中包含转换后的元素。时间复杂度是 O ( n ) O(n) O(n)

函数的形式如下:

func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]

下面是用 map 做数组类型转换的例子:

struct Person {
    var name: String
    var age: Int
}

// 创建一个Person对象数组
let peoples = [
    Person(name: "Alice", age: 30),
    Person(name: "Bob", age: 25),
    Person(name: "Charlie", age: 35)
]

// [Person] -> [String]
let names = peoples.map { $0.name }

print(names)  // 输出:["Bob", "Alice", "Charlie"]

需要注意的是,使用 map 函数不会自动帮我们去掉转换失败的 nil 值,如有相关诉求可以使用 compactMap 函数。

4. flatMap

flatMap 函数和上面提到的 map 函数相似,也是用于对每个元素做转换,返回一个新的集合;但是不太一样的是,它对每个元素转换的返回值可以是集合类型的,然后会将所有的结果集合合并成一个,常用于做数据打平操作(例如将二维数组转一维)。时间复杂度是 O ( n + m ) O(n + m) O(n+m),其中 n n n 是数组长度, m m m 是结果长度。

函数的形式如下:

func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence

下面是利用 flatMap 函数将二维数组转一维的例子:

let numbers = [1, 2, 3, 4]

// [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]]
let mapped = numbers.map { Array(repeating: $0, count: $0) }
     
let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }
print(flatMapped) // 输出: [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]

5. compactMap

compactMap 函数的作用和 mapflatMap 函数一样,唯一不同的是它会剔除结果集合中转换失败的 nil。时间复杂度是 O ( n + m ) O(n + m) O(n+m),其中 n n n 是数组长度, m m m 是结果长度。

函数的形式如下:

func compactMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

下面是利用 mapcompactMap 做对象转换的对比例子。

let possibleNumbers = ["1", "2", "three", "///4///", "5"]

let mapped: [Int?] = possibleNumbers.map { str in Int(str) }
print(mapped) // Prints: [1, 2, nil, nil, 5]

// 通过 compactMap 转换,会剔除转换失败产生的 nil 值
let compactMapped: [Int] = possibleNumbers.compactMap { str in Int(str) }
print(compactMapped) // Prints: [1, 2, 5]

6. reduce

reduce 函数主要用于遍历集合类型对象来进行求值,或构造一个新集合类型对象等,时间复杂度是 O ( n ) O(n) O(n)

函数的形式如下:

// 传入闭包有返回值,常用于遍历求值
func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

// 传入闭包无返回值,常用构建新集合类型对象
func reduce<Result>(into initialResult: Result, _ updateAccumulatingResult: (inout Result, Element) throws -> ()) rethrows -> Result

6.1 对数组求和

let sizes = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
// 利用 reduce 求元素累加
let totalSize = sizes.reduce(0, { $0 + $1 })
print(totalSize) // 输出: 30

如果只是单纯想做累加,或者累乘操作,可以像下面简写成运算符号。

// 利用 reduce 求元素累加
let totalSize = sizes.reduce(0, +)

6.2 求数组最值

let nums = [1, 4, 54, -4, 5]
// 求最小值
let minNum = nums.reduce(Int.max) { partialResult, num in
    return min(partialResult, num)
}
print(minNum) // 输出: -4

6.3 构建新集合类型对象

下面是一个利用 reduce 函数构建字典的例子

struct Person {
    var name: String
    var age: Int
}

// 创建一个Person数组对象
let peoples = [
    Person(name: "Alice", age: 30),
    Person(name: "Bob", age: 25),
    Person(name: "Charlie", age: 35)
]

// 构建一个 key 是 name,value 是 age 的数组
let infoMap = peoples.reduce(into: [String: Int]()) { partialResult, person in
    partialResult[person.name] = person.age
}

print(infoMap) //输出: ["Charlie": 35, "Bob": 25, "Alice": 30]

7. sorted

sorted 是 swift 提供的排序函数,时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)

函数的形式如下:

// 对数组原地排序,要数组对象声明为 `var`
mutating func sort(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows

// 对数组排序,不改变原来的数组,返回结果数组
func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]

7.1 对基本类型排序

下面是将字符串按字典序从小到大排序例子

let students: Set = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]
// 排序
let sortedStudents = students.sorted(by: {$0 < $1 })
print(sortedStudents)
// Prints: ["Abena", "Akosua", "Kofi", "Kweku", "Peter"]

还有下面这种简便写法,直接用比较符号表示升降序。

let sortedStudents = students.sorted(by: <)

也可以这样,因为默认传的就是 <

let sortedStudents = students.sorted()

需要注意的是,如果你对自定义类型使用这种简便写法,那么你需要为该类型实现 Comparable 协议,以便排序算法能够正确比较元素的大小和相等性。

7.2 对自定义类型排序

下面是对自定义的 Person 数组对象,按照年龄大小降序排序的例子。

struct Person {
    var name: String
    var age: Int
}

// 创建一个Person数组对象
let peoples = [
    Person(name: "Alice", age: 30),
    Person(name: "Bob", age: 25),
    Person(name: "Charlie", age: 35)
]

// 通过闭包表明 Person 对象排序规则
let sortedPeoples = peoples.sorted { p1, p2 in
	// 按照年龄降序排序
    return p1.age > p2.age
}

print(sortedPeoples)

按照前文提到的,如果要对自定义类型使用简便写法(传入的比较的闭包简写成符号),就要让自定义类型实现 Comparable 协议。

// 实现 Comparable 协议
// MARK: - Comparable
extension Person: Comparable {
    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.age < rhs.age
    }
}

// 使用简便写法
let sortedPeoples = peoples.sorted(by: >)

参考资料

https://developer.apple.com/documentation/swift/sequence/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值