Удалить дубликаты из массива Int в Swift (for-in-l oop) - PullRequest
0 голосов
/ 03 марта 2020

Существует множество способов удаления дубликатов из массива в swift, но я пытаюсь использовать для в l oop для управления этим. Кто-нибудь может объяснить, почему этот код не работает?

Неустранимая ошибка: индекс выходит за пределы диапазона

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)

Ответы [ 2 ]

1 голос
/ 03 марта 2020

Проблемная часть c состоит в том, чтобы выполнять итерацию по массиву и обновлять этот массив одновременно. В этом случае удаление элемента во время итерации.

Удаление элемента уменьшает длину массива (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 для хранения добавленных элементов:

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 } 
0 голосов
/ 03 марта 2020

Одна из причин в том, что вы модифицируете тот же массив, в котором вы запускаете два цикла for. Чтобы разобраться в деталях, используйте отладчик, как говорит Мартин. И

Это можно сделать, используя один для l oop и Set:

var newArray = [0, 1, 8, 3, 4, 4, 3, 6, 7, 11, 4, 5, 5, 8]
var array = Set<Int>()
for i in  newArray {
    array.insert(i)
}
print(array)

вывод:

[4, 5, 3, 0, 1, 8, 6, 11, 7]
...