Swift——高阶函数(map、filter、reduce、forEach、sorted、contains……)

本文主要讲解 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 就像一个 "检测器":遍历集合并检查是否存在符合要求的元素,无需手动遍历判断,代码更简洁。

  • 有两个常用变体:
    1. contains(_:):检查是否包含具体某个元素 (要求元素遵循 Equatable 协议,如 Int、String、CGSize 等默认遵循)
    2. contains(where:):检查是否包含符合自定义条件的元素(更灵活,适用于复杂判断)
  • 返回值是 Booltrue= 包含,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会延迟计算,直到真正需要结果时才执行操作,避免创建大量中间数组。

相关推荐
妮妮分享2 小时前
维智地图如何集成
开发语言·ios·swift
2501_915921432 小时前
iPhone HTTPS 抓包在真机环境下面临的常见问题
android·ios·小程序·https·uni-app·iphone·webview
2501_915918413 小时前
iOS 图片资源保护方法,分析图片在二次打包和资源篡改中的实际风险
android·ios·小程序·https·uni-app·iphone·webview
TheNextByte13 小时前
如何通过 7 种方式将视频从 iPhone 传输到 U 盘?
ios·音视频·iphone
Zender Han3 小时前
Flutter EasyRefresh 最新版本:自定义 Header / Footer 详解与实践
android·flutter·ios
Sheffi664 小时前
iOS 锁的本质:互斥锁、自旋锁、递归锁深度解析
ios
夜-未央4 小时前
iOS QQ分享报错:应用未正确授权(错误码:25105)
ios
大猫熊猫4 小时前
【ios】xcode运行项目时报错 Showing All Errors Only Framework ‘Pods_Runner‘ not found
macos·ios·xcode
2501_916008894 小时前
iPhone 耗电异常检测的思路,从系统电池统计、克魔(KeyMob)、Instruments等工具出发
android·ios·小程序·uni-app·cocoa·iphone·webview