P
Basically the objective of the function checker is to remove duplicates from a list of previously ordered in ascending order. Under this premise we will see if we clarify the causes of your judgment.First of all, some observations:To efficiently remove duplicates from a better list see the following question and their answers: https://es.stackoverflow.com/q/87813/15089 The purpose of this answer does not discuss the most efficient methods for this purpose.Although the handling of exceptions is common in Python, it does not mean that it is always a good solution, the most efficient and much less becoming a norm. In this case the handling of exceptions is used to protect from indexing on an invalid index, as we have all the information necessary to avoid a IndexError Better to prevent the algorithm from generating such an exception.Given that pop acts on the list itself, I'll assume you're trying to remove duplicates. in-place. With this in mind, if a function or method acts in-place about an object (in addition to documenting it correctly) never should at once return it.There are ways to avoid directly that the list has duplicates. For example, since the range of values destined to populate the list is small (enters from 1 to 10), use random.sample is a very simple option:import random
lista = random.sample(range(1, 11), k=random.randint(1, 10))
The idea under the function is actually simple, since we have the orderly list, we iterated on it comparing an element with the following, if they are equal we remove all duplicates before passing to the next index. Before you see why it doesn't work, it's important to clarify the functioning of list.pop and filter:list.pop(i): removes and returns the element in the index i from the list. If you don't mind ieliminates and returns the last element of it.filter(funcion, iterable): basically what it does is to iterate about the iterable, call the function for each item of the same and stay only with those elements for which the function returns True. Yeah. funcion That's it. None the identity function is assumed and it is left only with the elements that are evaluated as certain (squalls different from 0, iterables not empty, etc.). Therefore, the function to receive an argument and on the basis of it return a boolean.In Python 2 returns a new list with the elements that pass the filter, in Python 3 returns an object filterAn iterable. In no case modifies the original iterable.For example, if we want to stay with the odd numbers on a list we can do the following:>>> def es_impar(n: int) -> bool:
... return n % 2 != 0
...
>>> lista = [1, 8, 5, 2, 13, 7, 4, 6]
>>> lista_filtrada = list(filter(es_impar, l))
>>> lista_filtrada
[1, 5, 13, 7]
In case a non-functional approach clarifies what it does filterbasically the previous concrete case "equivale" to:lista_filtrada = []
for elemento in lista:
if es_impar(elemento):
lista_filtrada.append(elemento)
or using list comprehensions:lista_filtrada = [elemento for elemento in lista if es_impar(elemento)]
So what's wrong with the function?As stated filter receives a function as a first argument (any "callable" actually), if we pass it x.pop(equal) what we are going through is the return of the method since we are calling it, that is, we pass the value of the item with index equal that just got deleted from the list, an integer. In summary filter He does absolutely nothing., filter(x.pop(equal), x) is the same as the result that x.pop(equal)except because in Python 2 it generates a TypeError. The above if the index passed to pop exists, because in any case We should pass the variable. i a pop (the element index) not equal (its value). So, filter(x.pop(equal), x) or ends with a IndexError without doing anything because pop receives an invalid index or removes a single item from the list (the one in the position equal, which may not be equal or a duplicate of this...). If we're lucky removes a single duplicate, for example in the case of [1, 1, 1, 2, 3], the first iteration compares x[0] == x[1] (1 ==1) and it happens that index 1 points to an element with value 1, so it remains [1, 1, 2, 3] after x.pop(1), the following iteration fails because only one element has been removed but we advance with the indexed one position, being the comparison x[1] == x[2] (1 == 2). This, if we're lucky, because [4, 4, 4, 5, 6, 7] compared in the first iteration 4 == 4 And call x.pop(4) which produces [4, 4, 4, 5, 7], we killed the poor 6 who had done nothing, but here does not end the thing, in the next iteration is compared x[1] == x[2] (4 == 4) and we call again x.pop(4) and in the end the function returns [4, 4, 4, 5]...In reality the idea in general is correct, it is the implementation that fails, filter is not appropriate for this, not if we want to remove duplicates on the list itself (and if we want to return a new one, I don't think of a way that is not ugly and inefficient using it filter...). For example, we can do the following:def eliminar_duplicados(x: list) -> None:
'''
Elimina los elementos duplicados de una lista previamente ordenada
'''
i: int = 0
for _ in range(len(x) - 1):
if x[i] == x[i + 1]:
del x[i]
else:
i += 1
>>> l = [1, 1, 1, 2, 2, 3, 5, 5, 8, 8, 13]
>>> eliminar_duplicados(l)
>>> l
[1, 2, 3, 5, 8, 13]
Two notes, could be used pop instead of del, but since we don't need the deleted item from the list doesn't make sense. On the other hand, that the list is ordered allows us to have the number of iterations to remove all duplicates known and equals the number of items on the list minus one. That's it. len(x) - 1 because logically the last element is not with whom to compare it and avoids the consequent IndexError.