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
相关产品推荐
相关产品推荐

