首页 > 解决方案 > 从 Swift 中的 Int 数组中删除重复项(for-in-loop)

问题描述

有很多方法可以快速从数组中删除重复项,但我正在尝试使用for in 循环来管理它。谁能解释一下,为什么这段代码不起作用?

致命错误:索引超出范围

func deleteDuplicates(array: [Int]) -> [Int] {

    var newArray = array

    for i in 0 ..< newArray.count - 1  {
        for j in i + 1 ..< newArray.count  {

            if newArray[i] == newArray[j] {
                newArray.remove(at: j)
            }
        }
    }
    return newArray
}

array1 = [0, 1, 8, 3, 4, 4, 3, 6, 7, 11, 4, 5, 5, 8]
deleteDuplicates(array: array1)

标签: arraysswiftduplicatesfor-in-loop

解决方案


有问题的部分是迭代一个数组并同时更新该数组。在这种情况下,在迭代时删除一个元素。

移除一个元素会减少数组长度 ( count) 并且还会改变索引。因此在

for j in i + 1 ..< array.count  {
    if array[i] == array[j] {
        newArray.remove(at: j)
    }
}

删除第一个索引后,您的其他索引将变为无效。请注意count,在实际迭代之前,它总是只读一次。

这就是为什么在迭代期间删除元素是危险和复杂的原因之一。您可以通过维护已删除元素的数量并相应地更新索引来修复它。或者您可以向后迭代:

var newArray = array

for i in (0 ..< newArray.count - 1).reversed()  {
    for j in (i + 1 ..< newArray.count).reversed()  {
        if newArray[i] == newArray[j] {
            newArray.remove(at: j)
        }
    }
}
return newArray

您仍在更改索引,count但由于您正在向后迭代,您只更改已使用的索引。

一般来说,构建一个新数组而不是更新当前数组更简单、更安全:

var newArray: [Int] = []

for value in array {
    if !newArray.contains(value) {
       newArray.append(value)
    }
}

return newArray

Set通过使用 a保留添加的元素,可以大大降低复杂性(性能) :

var newArray: [Int] = []
var foundElements: Set<Int> = []

for value in array {
    if foundElements.insert(value).inserted {
       newArray.append(value)
    }
}

return newArray

可以使用以下方法简化filter

var foundElements: Set<Int> = []
return array.filter { foundElements.insert($0).inserted } 

推荐阅读