4

I should not use advance function, as this is a logical test during interview. Trying to remove all digits which appear more than once in array.

testcase: a=[1,1,2,3,2,4,5,6,7]

code:

    def dup(a):
      i=0
      arraySize = len(a)
      print(arraySize)
        while i < arraySize:
        #print("1 = ",arraySize)
        k=i+1
          for k in range(k,arraySize):
          if a[i] == a[k]:
          a.remove(a[k])
        arraySize -= 1
        #print("2 = ",arraySize)
      i += 1
    print(a) 

result should be : 1,2,3,4,5,6,7

But i keep getting index out of range. i know that it is because the array list inside the loop changed, so the "while" initial index is different with the new index.

The question is : any way to sync the new index length (array inside the loop) with the parent loop (index in "while" loop) ?

The only thing i can think of is to use function inside the loop.

any hint?

  • 2
    "...because the array list inside the loop changed". You're on the right track. Because you *are* modifying the list while you are iterating, and then you get to an index that does not exist, you will get this error. For your current implementation, you should use an entirely new list and just append to the list when you find a value that doesn't exist in the list already. Side note, your solution can be summed as `list(set(a))`. – idjaw Jul 23 '18 at 03:37
  • Never alter the object you are iterating over in Python; the iterator will not be updated. – pstatix Jul 23 '18 at 03:47
  • To provide you with some more of an explanation, there is a question that touches on modifying the same list you are iterating [here](https://stackoverflow.com/questions/6260089/strange-result-when-removing-item-from-a-list). – idjaw Jul 23 '18 at 03:48

2 Answers2

3

Re-Calculating Array Size Per Iteration

It looks like we have a couple issues here. The first issue is that you can't update the "stop" value in your inner loop (the range function). So first off, let's remove that and use another while loop to give us the ability to re-calculate our array size every iteration.

Re-Checking Values Shifted Into Removed List Spot

Next, after you fix that you will run into a larger issue. When you use remove it moves a value from the end of the list or shifts the entire list to the left to use the removed spot, and you are not re-checking the value that got moved into the old values removed spot. To resolve this, we need to decrement i whenever we remove an element, this makes sure we are checking the value that gets placed into the removed elements spot.

remove vs del

You should use del over remove in this case. remove iterates over the list and removes the first occurrence of the value and it looks like we already know the exact index of the value we want to remove. remove might work, but it's usage here over complicates things a bit.

Functional Code with Minimal Changeset

def dup(a):
    i = 0
    arraySize = len(a)
    print(arraySize)
    while i < arraySize:
        k = i + 1
        while k < arraySize: # CHANGE: use a while loop to have greater control over the array size.
            if a[i] == a[k]:
                print("Duplicate found at indexes %d and %d." % (i, k))
                del a[i] # CHANGE: used del instead of remove.
                i -= 1 # CHANGE: you need to recheck the new value that got placed into the old removed spot.
                arraySize -= 1
                break
            k += 1
        i += 1
    return a

Now, I'd like to note that we have some readability and maintainability issues with the code above. Iterating through an array and manipulating the iterator in the way we are doing is a bit messy and could be prone to simple mistakes. Below are a couple ways I'd implement this problem in a more readable and maintainable manner.

Simple Readable Alternative

def remove_duplicates(old_numbers):
    """ Simple/naive implementation to remove duplicate numbers from a list of numbers. """
    new_numbers = []
    for old_number in old_numbers:
        is_duplicate = False
        for new_number in new_numbers:
            if old_number == new_number:
                is_duplicate = True
        if is_duplicate == False:
            new_numbers.append(old_number)
    return new_numbers

Optimized Low Level Alternative

def remove_duplicates(numbers):
""" Removes all duplicates in the list of numbers in place. """
    for i in range(len(numbers) - 1, -1, -1):
        for k in range(i, -1, -1):
            if i != k and numbers[i] == numbers[k]:
                print("Duplicate found. Removing number at index: %d" % i)
                del numbers[i]
                break
    return numbers
Brennen Sprimont
  • 1,564
  • 15
  • 28
0

You could copy contents in another list and remove duplicates from that and return the list. For example:

duplicate = a.copy()  

f = 0  
for j in range(len(a)):  
    for i in range(len(duplicate)):  
        if i < len(duplicate):  
            if a[j] == duplicate[i]:  
                f = f+1  
                if f > 1:  
                    f = 0  
                    duplicate.remove(duplicate[i])  
    f=0  
print(duplicate) 
kkblue
  • 183
  • 10