Introdução à programação
com Python em um contexto visual


Removendo itens de coleções

Removendo itens de uma lista

Imagine que temos uma lista com números. Podemos obter o número em uma determinada posição (índice) ao mesmo tempo que o removemos, como o método .pop(). Se chamarmos .pop() sem nenhum argumento removemos o último item da lista. Passando um índice a operação se torna um pouco menos eficiente para listas muito grandes mas funciona também.

numeros = [10, 20, 30, 40, 50, 60, 70, 80, 90]
a = numeros.pop() # remove o 90, a = 90
b = nomeros.pop(0) # remove o 10, b = 10 
print(numeros) # exibe [20, 30, 40, 50, 60, 70, 80]

Também é possível usar a instrução del com o índice.

numeros = [100, 200, 300]
del numeros[1]
print(numeros) # exibe [100, 300]
del numeros[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range

Tanto com del lista[indice] como com lista.pop(indice) é preciso garantir que o índice cai dentro da lista!

Outra maneira de remover itens de uma lista é o método .remove(valor), nesse caso a primeira instância encontrada do valor vai ser removida.

numeros = [2, 5, 2, 5, 2, 5, 2]
numeros.remove(5)
print(numeros) # exibe [2, 2, 5, 2, 5, 2]
numeros.remove(6)
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: list.remove(x): x not in list

Tentar remover um valor que não está contido na lista produz um erro, você pode checar antes com if x in numeros: numeros.remove(x).

Não remova itens ao mesmo tempo em que percorre uma coleção

Quando queremos remover itens de uma estrutura de dados “dinâmica” isto é com número variável de itens, como uma lista, se tentarmos remover itens em uma iteração (como um laço for) que percorre a mesma estrutura que vamos modificar, acabamos por ter problemas.

Um exemplo comum na programação criativa é termos um sistema de partículas que são objetos que interagem e se desenham na tela, mas precisamos remover alguns deles depois de algum tempo, por “decaimento”/morte ou caso saiam da tela. O exemplo a seguir é bem mais simples que isso, são só alguns números em uma lista e queremos remover os zeros:

# errado

numeros = [1, 2, 4, 0, 0, 0, 0, 8, 0, 9, 0]
for n in numeros:
    print(n)
    if  n == 0:
        numeros.remove(n)

print(numeros)  # exibe: [1, 2, 4, 8, 0, 9, 0]

Uma das soluções possíveis é copiar a estrutura e “andar” pela cópia enquanto se remove itens da estrutura original.

# certo

numeros = [1, 2, 4, 0, 0, 0, 0, 8, 0, 9, 0]
for n in numeros.copy():
    if  n == 0:
        numeros.remove(n)
        
print(numeros)  # exibe  [1, 2, 4, 8, 9]

Em vez numeros.copy() é possível também usar numeros[:], que é uma ‘fatia’ contendo uma cópia da lista toda, ou ainda a função embutida reversed(), que cria um objeto iterável e também pode ser usada neste caso. Essa última forma lembra a estratégia de iteração do final para o começo usada em outras linguagens que necessitam de um índice para consultar os itens da coleção.

numeros = [1, 2, 4, 0, 0, 0, 0, 8, 0, 9, 0]
for n in reversed(numeros):
    if  n == 0:
        numeros.remove(n) 
        
print(numeros)  # exibe  [1, 2, 4, 8, 9]

# experimente também: `for i, n in reversed(list(enumerate(numeros))):`
# E nesse caso é possível usar `del numeros[i]` ou `numeros.pop(i)`

Criando uma nova lista filtrando os valores a serem removidos

Uma outra solução é construir uma nova lista sem os itens que você quer remover, seja com um laço também ou com uma compreensão de listas como no exemplo abaixo:

numeros = [1, 2, 4, 0, 0, 0, 0, 8, 0, 9, 0]
numeros = [n for n in numeros if n != 0]   # compreensão de listas

Em caso de listas grandes isso pode fazer boa diferença em termos de performance, uma vez que remover itens do meio de uma lista não é muito eficiente.