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?

3
  • 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)). Commented Jul 23, 2018 at 3:37
  • Never alter the object you are iterating over in Python; the iterator will not be updated. Commented Jul 23, 2018 at 3: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. Commented Jul 23, 2018 at 3:48

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

3 Comments

wow. it works without the index error. is it because backward looping?
ah i understand now, because the "i" variable increase (or decrease) together with the "number[i]". smart! thanks.
I think you have it, by iterating backwards we avoid needing to re-calculate the size of the array every iteration. We also avoid the "shift" issue described in the first sentence of my answer.
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) 

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.