To address why your code isn't working, it is due to the fact that you initialise j
at the start of the function, so after the first iteration of the i
loop, it is len(item)-1
and then never get's reset for future loops.
This means that you miss many duplicates.
So since we need to initialise it each loop, we still need to know what to. If we initialise it as 0
, then we are checking for duplicates behind the current j
value in the list so this is a waste of time. To improve efficiency, we should initialise it as i+1
so that we check numbers after i
for duplicates as we already know that there are no duplicates of the value at i
before the index i
in the list. This also simplifies the if
as we no longer need to check i != j
.
And one final thing is that when you delete j
with del
, all the indexes after are now shifted down by one. So we also need to subtract 1
from j
so that we now check the element straight after the one we just deleted which is now at the same index of the one we just deleted (since they are shifted down).
So, in code:
def duplicated(item):
i = 0
while i < len(item):
j = i + 1
while j < len(item):
if item[j] == item[i]:
del item[j]
j -= 1
j += 1
i += 1
return item
and it works with the examples people have given:
>>> duplicated([1,2,3,4,5,6,7,8,9,1,2,6,7])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> duplicated([1,2,3,4,5,6,7,8,9,1,1,2,6,7])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
However, this solution is current of complexity O(n^2)
since we are using nested loops so the time taken is proportional to the size of the input list squared.
But if we were able to modify the algorithm to use only one loop, we would reduce the complexity to O(n)
. This can be done by using a set for lookup. Adding and checking if an element is in the set is O(1)
(average case) so we can use them to speed things up.
So if we have a set which contains the elements we have already seen, then for each future element, if it is already in the seen
set, we delete it, otherwise we add it to this set.
So, in code:
def duplicated(item):
seen = set()
i = 0
while i < len(item):
if item[i] in seen:
del item[i]
else:
seen.add(item[i])
i += 1
return item
And I can confirm that this passes the test cases above as well.
One last thing I should point out is that when deleting the element here, I did not subtract from the pointer, this is because before we subtracted as we knew it would later be incremented and we wanted it to be the same, however here, it is only incremented in the else
block, so if we don't do anything, it will stay the same.