-1

There are a lot of methods to remove duplicates from an array in swift, but I'm trying to use a for in loop to manage that. Can any one explain, why this code doesn't work?

Fatal error: Index out of range

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)
3
  • Your's nested loop causing this crash. Commented Mar 3, 2020 at 9:07
  • A better approach here is to loop over array and adding values in the loop instead to newArray Commented Mar 3, 2020 at 9:23
  • This should do it : func deleteDuplicates(array: [Int]) -> [Int] { return Array(NSOrderedSet(array: array)) as? [Int] ?? array } Commented Mar 3, 2020 at 9:42

3 Answers 3

2

The problematic part is to iterate over an array and update that array at the same time. In this case, removing an element while iterating.

Removing an element decreases array length (count) and also changes indices. Therefore in

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

After removing the first index, your other indices become invalid. Note that count is always read only once, before the actual iteration.

This is one of the reasons why removing elements during iteration is dangerous and complicated. You could fix it by maintaining the number of removed elements and update indices accordingly. Or you can iterate backwards:

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

You are still changing indices and count but since you are iterating backwards, you only change the indices that have been already used.

In general it's simple and safer to build a new array instead of updating the current one:

var newArray: [Int] = []

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

return newArray

which can be very reduced in complexity (performance) by using a Set to keep added elements:

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

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

return newArray

Which can be simplified using filter:

var foundElements: Set<Int> = []
return array.filter { foundElements.insert($0).inserted } 
Sign up to request clarification or add additional context in comments.

Comments

0

One Reason is you are modifying the same array on which you are running two for loops. To understand in details, use the debugger as Martin says. And

This can be done using one for loop and 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)

output:

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

2 Comments

What you are doing is incorrect. You are not keeping the original order.
@Sulthan, I understand. I showed a way to remove duplicates. OP didn't mention anything about keeping the order.
0

Here is one simple approach that you can try.

func removeDuplicates(_ nums: inout [Int]) {    
        var arrLen = nums.count
        var index = 0
        while(index < arrLen - 1){
            if nums[index] == nums[index+1] {
                nums.remove(at: index)
                arrLen = arrLen - 1
            }else{
                index = index+1
            }
        }
    }

It removes duplicates inplace without the need for new array being created.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.