本文主要讲解 map、filter、reduce、forEach、sorted、contains 、 first(where:) / last(where:) 、firstIndex 和 lastIndex 、prefix( :) 和 dropFirst( :) 、 allSatisfy(_:) 、 lazy:延迟加载
一、map
map 函数,Swift 中最常用的高阶函数之一,核心作用是将集合中的每个元素按照指定规则转换,返回一个新的同类型集合 ,非常适合批量处理数组、字典等集合类型的元素。 map 就像一个 "转换器":遍历集合中的每一个元素,把每个元素传入你定义的转换规则(闭包),然后将转换后的结果收集起来,形成一个新的集合返回。
- 原集合不会被修改(纯函数特性)
- 新集合的元素数量和原集合完全一致
- 新集合的元素类型可以和原集合不同
Swift
let prices = [100,200,300]
let discountedPrices = prices.map{$0 * 10}
print(discountedPrices) // [1000, 2000, 3000]
let cast = ["Vivien", "Marlon", "Kim", "Karl"]
let lowercaseNames = cast.map{$0.lowercased()}
print(lowercaseNames) // ["vivien", "marlon", "kim", "karl"]
let letterCounts = cast.map{$0.count}
print(letterCounts)// [6, 6, 3, 4]
二、 filter
filter 函数和 map 并列的核心高阶函数,filter的核心作用是根据指定条件筛选集合中的元素,返回符合条件的新集合 ,非常适合从数组、字典等集合中 "挑选" 需要的元素。 filter 就像一个 "筛选器":遍历集合中的每一个元素,把每个元素传入你定义的判断条件(闭包),只有满足条件(闭包返回 true)的元素会被保留,最终返回一个包含所有符合条件元素的新集合。
- 原集合不会被修改
- 新集合的元素数量 ≤ 原集合
- 新集合的元素类型和原集合完全一致
Swift
// 示例1:筛选数字数组中的偶数
let numbers = [1, 2, 3, 4, 5, 6, 7, 8]
let evenNumbers = numbers.filter { number in
return number % 2 == 0
}
print(evenNumbers) // 输出:[2, 4, 6, 8]
// 简化写法
let evenNumbersShort = numbers.filter { $0 % 2 == 0 }
print(evenNumbersShort) // 输出:[2, 4, 6, 8]
// 示例2:筛选字符串数组中长度大于5的元素
let fruits = ["apple", "banana", "orange", "grape", "watermelon"]
let longFruits = fruits.filter { $0.count > 5 }
print(longFruits) // 输出:["banana", "orange", "watermelon"]
bash
// 示例3:筛选自定义对象数组(比如筛选年龄≥18的用户)
struct User {
let name: String
let age: Int
}
let users = [
User(name: "张三", age: 17),
User(name: "李四", age: 20),
User(name: "王五", age: 25)
]
let adultUsers = users.filter { $0.age >= 18 }
print(adultUsers.map { $0.name }) // 输出:["李四", "王五"]
三、reduce
reduce 核心作用是将集合中的所有元素 "归约"/"汇总" 成一个单一的值(比如求和、拼接字符串、计算总宽度、生成字典等),可以理解为把一组元素 "压缩" 成一个结果。
reduce 就像一个 "汇总器":从一个初始值开始,遍历集合中的每一个元素,将当前元素与累计结果做指定运算,最终得到一个单一的汇总值。
- 原集合不会被修改
- 最终结果的类型可以和集合元素类型不同(比如数组元素是
Int,结果可以是String;元素是CGFloat,结果可以是CGFloat) - 核心逻辑:
初始值 + 元素1 → 累计值1 + 元素2 → 累计值2 + ... → 最终结果
typescript
// 示例1:数字数组求和(最基础用法)
let numbers = [1, 2, 3, 4, 5]
// 初始值为0,累计规则:累计值 + 当前元素
let sum = numbers.reduce(0) { partialSum, number in
return partialSum + number
}
// 简化写法
let sumShort = numbers.reduce(0, +) // 直接用运算符简写,等价于上面的闭包
print(sum) // 输出:15
// 示例2:字符串数组合并成一个完整字符串
let words = ["Hello", " ", "Swift", " ", "reduce!"]
// 初始值为空字符串,累计规则:拼接字符串
let sentence = words.reduce("") { $0 + $1 }
print(sentence) // 输出:"Hello Swift reduce!"
// 示例3:计算数组中最大值(初始值设为最小值)
let scores = [85, 92, 78, 95, 88]
let maxScore = scores.reduce(Int.min) { max($0, $1) }
print(maxScore) // 输出:95
四、 forEach
forEach 函数,它是集合的基础遍历方法,核心作用是遍历集合中的每一个元素并执行指定操作 ,和传统的 for-in 循环功能类似,但写法更简洁,且是函数式编程风格的遍历方式。
forEach 就像一个 "遍历执行器":按顺序遍历集合中的每一个元素,对每个元素执行你定义的闭包操作(比如打印、修改属性、调用方法等)。
- 原集合不会被修改(除非你在闭包内主动修改元素的可变属性)
- 没有返回值(
Void),这是和map/filter/reduce最大的区别(后三者都返回新集合 / 值) - 无法用
break/continue中断 / 跳过遍历(如需中断,建议用传统for-in循环)
Swift
// 示例1:遍历打印数组元素
let fruits = ["apple", "banana", "orange"]
fruits.forEach { fruit in
print("水果:\(fruit)")
}
// 简化写法
fruits.forEach { print("水果:\($0)") }
Swift
let numbers = [1, 2, 3, 4, 5]
// 需求:遍历到3时停止
// ❌ forEach 无法中断,会遍历所有元素
numbers.forEach {
if $0 == 3 {
return // 仅跳过当前元素,不会中断整体遍历
}
print($0) // 输出:1,2,4,5
}
// ✅ for-in 可以中断
for number in numbers {
if number == 3 {
break // 直接中断遍历
}
print(number) // 输出:1,2
}
五、 sorted 排序
sorted 函数,它是集合中用于排序的核心高阶函数,核心作用是将集合中的元素按指定规则排序,返回一个新的有序集合(原集合保持不变)。
Swift
// 示例1:数字数组默认排序(升序)
let numbers = [5, 2, 9, 1, 7]
let sortedNumbers = numbers.sorted()
print(sortedNumbers) // 输出:[1, 2, 5, 7, 9]
// 示例2:自定义降序排序
let descendingNumbers = numbers.sorted { $0 > $1 }
print(descendingNumbers) // 输出:[9, 7, 5, 2, 1]
// 示例3:字符串数组排序(默认字母序,区分大小写)
let fruits = ["banana", "Apple", "orange", "grape"]
let sortedFruits = fruits.sorted()
print(sortedFruits) // 输出:["Apple", "banana", "grape", "orange"]
// 示例4:字符串忽略大小写排序(自定义规则)
let caseInsensitiveFruits = fruits.sorted { $0.lowercased() < $1.lowercased() }
print(caseInsensitiveFruits) // 输出:["Apple", "banana", "grape", "orange"](和上面结果一样,但逻辑更通用)
六、contains
contains 函数,它是集合用于判断 "是否包含指定元素 / 符合条件的元素" 的核心方法,核心作用是快速检查集合中是否存在目标元素或满足条件的元素 ,返回布尔值(true/false)。 contains 就像一个 "检测器":遍历集合并检查是否存在符合要求的元素,无需手动遍历判断,代码更简洁。
- 有两个常用变体:
contains(_:):检查是否包含具体某个元素 (要求元素遵循Equatable协议,如 Int、String、CGSize 等默认遵循)contains(where:):检查是否包含符合自定义条件的元素(更灵活,适用于复杂判断)
- 返回值是
Bool(true= 包含,false= 不包含) - 原集合不会被修改
Swift
// 示例1:检查是否包含具体数字
let numbers = [1, 2, 3, 4, 5]
let hasThree = numbers.contains(3)
let hasTen = numbers.contains(10)
print(hasThree) // 输出:true
print(hasTen) // 输出:false
// 示例2:检查是否包含具体字符串
let fruits = ["apple", "banana", "orange"]
let hasBanana = fruits.contains("banana")
print(hasBanana) // 输出:true
// 示例3:检查是否包含符合条件的元素(数字大于3)
let hasGreaterThanThree = numbers.contains { $0 > 3 }
print(hasGreaterThanThree) // 输出:true(4、5都满足)
// 示例4:检查是否包含长度大于5的字符串
let hasLongFruit = fruits.contains { $0.count > 5 }
print(hasLongFruit) // 输出:true(banana、orange长度都大于5)
七、 first(where:)和last(where:)
first(where:) 和 last(where:) 方法,它们是集合中用于精准查找第一个 / 最后一个符合条件元素 的核心方法,返回值是可选类型(T?)------ 找到则返回对应元素,找不到则返回 nil。
first(where:) / last(where:) 就像 "精准查找器":
first(where:):从前往后 遍历集合,返回第一个满足条件的元素(可选值)last(where:):从后往前 遍历集合,返回最后一个满足条件的元素(可选值)- 两者都不会修改原集合,且找到目标元素后会立即停止遍历(性能优于先
filter再取first/last) - 若集合为空或无符合条件的元素,返回
nil
Swift
// 示例1:查找第一个大于3的数字
let numbers = [1, 2, 3, 4, 5, 4, 3]
let firstGreaterThan3 = numbers.first { $0 > 3 }
print(firstGreaterThan3) // 输出:Optional(4)(第一个满足的是索引3的4)
// 示例2:查找最后一个大于3的数字
let lastGreaterThan3 = numbers.last { $0 > 3 }
print(lastGreaterThan3) // 输出:Optional(4)(最后一个满足的是索引5的4)
// 示例3:查找第一个长度大于5的字符串
let fruits = ["apple", "banana", "orange", "grape"]
let firstLongFruit = fruits.first { $0.count > 5 }
print(firstLongFruit) // 输出:Optional("banana")
// 示例4:无符合条件元素时返回nil
let firstGreaterThan10 = numbers.first { $0 > 10 }
print(firstGreaterThan10) // 输出:nil
八、 firstIndex 和 lastIndex
firstIndex(of:) / firstIndex(where:) 和 lastIndex(of:) / lastIndex(where:) 方法,它们是集合中用于查找元素对应索引 的核心方法,返回值为可选类型的 Index(通常是 Int 类型)------ 找到则返回元素的索引,找不到则返回 nil。
| 方法 | 作用 | 适用条件 |
|---|---|---|
firstIndex(of:) |
从前往后找第一个匹配指定元素的索引 | 元素遵循 Equatable 协议 |
firstIndex(where:) |
从前往后找第一个符合自定义条件的元素的索引 | 无(更灵活,支持复杂判断) |
lastIndex(of:) |
从后往前找最后一个匹配指定元素的索引 | 元素遵循 Equatable 协议 |
lastIndex(where:) |
从后往前找最后一个符合自定义条件的元素的索引 | 无 |
- 所有方法返回值都是
Index?(数组中等价于Int?),找不到则返回nil - 找到目标后立即停止遍历,性能高效
- 原集合不会被修改
Swift
// 基础数组
let numbers = [1, 2, 3, 2, 5, 2]
let fruits = ["apple", "banana", "orange", "banana"]
// 示例1:firstIndex(of:) ------ 找第一个2的索引
if let firstTwoIdx = numbers.firstIndex(of: 2) {
print("第一个2的索引:\(firstTwoIdx)") // 输出:1
}
// 示例2:lastIndex(of:) ------ 找最后一个2的索引
if let lastTwoIdx = numbers.lastIndex(of: 2) {
print("最后一个2的索引:\(lastTwoIdx)") // 输出:5
}
// 示例3:firstIndex(where:) ------ 找第一个大于3的数字的索引
if let firstGreater3Idx = numbers.firstIndex { $0 > 3 } {
print("第一个大于3的数字索引:\(firstGreater3Idx)") // 输出:4(数字5)
}
// 示例4:lastIndex(where:) ------ 找最后一个"banana"的索引
if let lastBananaIdx = fruits.lastIndex { $0 == "banana" } {
print("最后一个banana的索引:\(lastBananaIdx)") // 输出:3
}
// 示例5:无匹配元素时返回nil
if let noExistIdx = numbers.firstIndex(of: 10) {
print(noExistIdx)
} else {
print("未找到元素10") // 输出:未找到元素10
}
九、prefix( :) 和 dropFirst( :)
prefix(:) 和 dropFirst(:) 方法,它们是集合中用于截取 / 剔除前 N 个元素 的核心方法,返回新的集合片段(PrefixSequence/DropFirstSequence,可直接转为数组),原集合保持不变。
| 方法 | 核心作用 | 返回值类型 | 原集合影响 |
|---|---|---|---|
prefix(_:) |
截取集合前 n 个元素(若 n 超过集合长度,返回全部元素) | PrefixSequence<T> |
无 |
dropFirst(_:) |
剔除集合前 n 个元素,返回剩余元素(若 n 超过集合长度,返回空集合) | DropFirstSequence<T> |
无 |
- 补充:还有无参数简化版
prefix()(等价于prefix(1),取第一个元素)、dropFirst()(等价于dropFirst(1),剔除第一个元素); - 返回的
Sequence可通过Array()转为普通数组,方便后续操作。
Swift
// 基础数组
let numbers = [1, 2, 3, 4, 5]
let fruits = ["apple", "banana", "orange", "grape"]
// 示例1:prefix(_:) ------ 截取前3个元素
let prefix3Numbers = Array(numbers.prefix(3))
print(prefix3Numbers) // 输出:[1, 2, 3]
// 示例2:prefix(_:) ------ n 超过数组长度,返回全部
let prefix10Numbers = Array(numbers.prefix(10))
print(prefix10Numbers) // 输出:[1, 2, 3, 4, 5]
// 示例3:dropFirst(_:) ------ 剔除前2个元素
let drop2Numbers = Array(numbers.dropFirst(2))
print(drop2Numbers) // 输出:[3, 4, 5]
// 示例4:dropFirst(_:) ------ n 超过数组长度,返回空
let drop10Numbers = Array(numbers.dropFirst(10))
print(drop10Numbers) // 输出:[]
// 示例5:无参数版
let firstFruit = Array(fruits.prefix(1)) // 等价于 prefix(1)
let restFruits = Array(fruits.dropFirst()) // 等价于 dropFirst(1)
print(firstFruit) // 输出:["apple"]
print(restFruits) // 输出:["banana", "orange", "grape"]
九、 allSatisfy(_:)
allSatisfy 方法,它是集合中用于判断所有元素是否都满足指定条件 的核心方法,返回布尔值(true/false)------ 只有当集合中每一个元素 都符合条件时返回 true,只要有一个不符合就返回 false。
allSatisfy 就像一个 "全量校验器":
- 遍历集合中的每一个元素,依次检查是否符合条件;
- 只要发现一个元素不符合条件,会立即停止遍历 (性能高效),返回
false; - 只有所有元素都符合条件,才会遍历完成并返回
true; - 对空集合 调用
allSatisfy会直接返回true(逻辑上 "空集合中所有元素都满足条件"); - 原集合不会被修改。
swift
// 基础数组
let numbers = [2, 4, 6, 8]
let mixedNumbers = [2, 4, 7, 8]
let fruits = ["apple", "banana", "orange"]
// 示例1:检查所有数字是否都是偶数
let allEven = numbers.allSatisfy { $0 % 2 == 0 }
print(allEven) // 输出:true
let mixedEven = mixedNumbers.allSatisfy { $0 % 2 == 0 }
print(mixedEven) // 输出:false(7是奇数,遍历到7时立即返回false)
// 示例2:检查所有字符串长度是否大于3
let allLongerThan3 = fruits.allSatisfy { $0.count > 3 }
print(allLongerThan3) // 输出:true(apple=5, banana=6, orange=6)
// 示例3:空集合调用返回true
let emptyArray: [Int] = []
let emptyAllMatch = emptyArray.allSatisfy { $0 > 10 }
print(emptyAllMatch) // 输出:true
十、 lazy:延迟加载
Swift
let hugeRange = 1...1000000
let result = hugeRange.lazy
.filter { $0 % 3 == 0 }
.map { $0 * 2 }
.prefix(10)
lazy会延迟计算,直到真正需要结果时才执行操作,避免创建大量中间数组。