Swift 4数组去重算法中移除元素时触发运行时错误求助
解决Swift数组去重时的索引越界问题
这个问题我太熟悉啦!你遇到的运行时错误是数组索引越界导致的,核心原因是你在遍历数组的同时修改了它的长度,让后续循环的索引超出了数组实际的范围。
问题分析
当你执行array.remove(at: i)时,数组的长度会立即减1,但你的循环范围是基于初始数组长度生成的0 ..< array.count。举个极端例子:如果输入数组是[4,4,4],第一次循环i=0,元素被加入集合;i=1时发现重复,执行移除操作,数组变成[4,4](长度为2);接下来循环会走到i=2,这时候array[2]根本不存在,直接触发索引越界崩溃。
解决方案1:反向遍历数组
最直接的修复方式是从后往前遍历数组。因为反向遍历时,你移除当前索引的元素不会影响还没遍历到的前面的索引(那些索引值更小,不会因为数组长度缩短而失效)。
修改后的代码:
func unique(_ arr:[Int]) -> [Int] { var array = arr var uniqueSet = Set<Int>() // 反向遍历,避免索引越界问题 for i in (0 ..< array.count).reversed() { if uniqueSet.contains(array[i]) { print("remove \(array[i]) for i \(i) from array") array.remove(at: i) } else { print("insert \(array[i]) into set") uniqueSet.insert(array[i]) } } return array } print(unique([1, 2, 4, 4, 5, 6]))
解决方案2:用Swift风格的方式构建新数组(更推荐)
其实不需要在原数组上修改,我们可以用reduce方法直接构建一个去重后的新数组,这样既不会有索引问题,代码也更简洁,还能保持原数组的顺序:
func unique(_ arr:[Int]) -> [Int] { var uniqueSet = Set<Int>() return arr.reduce(into: [Int]()) { result, element in if !uniqueSet.contains(element) { uniqueSet.insert(element) result.append(element) } } } print(unique([1, 2, 4, 4, 5, 6]))
这种方法的思路是遍历原数组,把第一次出现的元素加入结果数组和集合,后续重复的元素直接跳过,完全避免了修改数组长度带来的风险。
内容的提问来源于stack exchange,提问作者Maria 9905
相关产品推荐
相关产品推荐

