You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中不借助高阶函数,优化for循环查找大数组元素索引的方法

问题:不借助Swift高阶函数,优化超大数组的元素索引查找性能

已知Swift高阶函数的使用场景及用法,但希望不借助这类现成函数,优化基于for循环的数组元素查找过程。请问针对超大数组,查找目标元素索引时,是否有进一步提升性能的优化方案?

测试代码:

func test() {
    let array: Array<String> = ["A", "B", "C", "A", "Hello, world!", "B", "C", "Hello", "W"]
    for index in array.indices {
        if array[index].contains("Hello") {
            print(index)
        }
    }
}

运行结果:

4
7

优化方案

1. 按需终止遍历(针对单匹配需求)

如果只需要找到第一个符合条件的索引,找到后立刻跳出循环,避免遍历整个数组。这种优化对只需要单个结果的场景收益极大:

func testFindFirst() {
    let array: [String] = ["A", "B", "C", "A", "Hello, world!", "B", "C", "Hello", "W"]
    for index in array.indices {
        if array[index].contains("Hello") {
            print(index)
            break // 找到目标后直接终止循环
        }
    }
}

2. 并行拆分遍历(针对超大数据量)

利用多线程并行处理数组的不同分片,减少整体遍历时间。注意结果收集时要保证线程安全:

func testParallelSearch() {
    let array: [String] = ["A", "B", "C", "A", "Hello, world!", "B", "C", "Hello", "W"]
    var resultIndices = [Int]()
    let lock = NSLock() // 保证多线程写结果时的安全
    
    DispatchQueue.concurrentPerform(iterations: array.count) { index in
        if array[index].contains("Hello") {
            lock.lock()
            resultIndices.append(index)
            lock.unlock()
        }
    }
    
    // 并行执行会打乱顺序,按需排序后输出
    resultIndices.sort()
    resultIndices.forEach { print($0) }
}

注意:仅适合数组极大的场景,小数组使用反而会因为线程调度开销降低性能。

3. 预处理缓存(针对重复查找场景)

如果需要多次执行相同条件的查找,提前一次性遍历数组并缓存符合条件的索引,后续直接读取缓存即可:

// 提前预处理缓存,全局或类级别存储
let array: [String] = ["A", "B", "C", "A", "Hello, world!", "B", "C", "Hello", "W"]
let cachedHelloIndices = array.indices.filter { array[$0].contains("Hello") }

// 后续查询直接用缓存
func testWithCache() {
    cachedHelloIndices.forEach { print($0) }
}

该方案把单次O(n)的查找变成O(1)的读取,适合重复查询的高频场景。

4. 优化字符串匹配逻辑

系统默认的String.contains(_:)通用匹配在处理长字符串时效率一般,如果目标匹配串固定(比如这里的"Hello"),可以用更高效的KMP匹配算法替代,减少单个元素的匹配耗时:

// 实现KMP字符串匹配算法
func kmpMatch(text: String, pattern: String) -> Bool {
    let textChars = Array(text)
    let patternChars = Array(pattern)
    guard !patternChars.isEmpty else { return true }
    
    // 构建部分匹配表(LPS)
    var lps = Array(repeating: 0, count: patternChars.count)
    var longestPrefixLen = 0
    var i = 1
    while i < patternChars.count {
        if patternChars[i] == patternChars[longestPrefixLen] {
            longestPrefixLen += 1
            lps[i] = longestPrefixLen
            i += 1
        } else {
            if longestPrefixLen != 0 {
                longestPrefixLen = lps[longestPrefixLen - 1]
            } else {
                lps[i] = 0
                i += 1
            }
        }
    }
    
    // 执行匹配
    i = 0 // text的索引
    var j = 0 // pattern的索引
    while i < textChars.count {
        if patternChars[j] == textChars[i] {
            i += 1
            j += 1
        }
        if j == patternChars.count {
            return true
        } else if i < textChars.count && patternChars[j] != textChars[i] {
            j = j != 0 ? lps[j - 1] : 0
            if j == 0 { i += 1 }
        }
    }
    return false
}

// 使用优化后的匹配函数
func testOptimizedMatch() {
    let array: [String] = ["A", "B", "C", "A", "Hello, world!", "B", "C", "Hello", "W"]
    for index in array.indices {
        if kmpMatch(text: array[index], pattern: "Hello") {
            print(index)
        }
    }
}

5. 减少数组元素访问开销

用enumerated()同时获取索引和元素,避免每次循环通过array[index]间接访问元素的开销,代码也更简洁:

func testReduceAccess() {
    let array: [String] = ["A", "B", "C", "A", "Hello, world!", "B", "C", "Hello", "W"]
    for (index, element) in array.enumerated() {
        if element.contains("Hello") {
            print(index)
        }
    }
}

内容的提问来源于stack exchange,提问作者swiftPunk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 01:54:24