Filter elements from a Python list

Asked

Viewed 7,292 times

2

Guys I want to remove all numbers equal to 1, but is giving this error

list index out of range

Follow the program

lista= [2, 3, 1, 5, 1, 7, 8, 8, 9, 15, 1, 1]

qtd = len(lista)


for i in range(qtd):     

    if(lista[i]==1):
        lista.remove(lista[i])
        print("Removeu")
        print(lista)

    qtd = qtd - 1


print("Final",lista)
  • 1

    Why do qtd = qtd - 1? What logic did you imagine?

  • Because the size of the list was being immutable. For example the list has 11 elements and the "for" would always be 11, but when you entered the if was to decrease the size and update the "for". Because when you enter if you remove an element

  • Exactly. That’s why you can’t do it the way you tried to do it. You can’t iterate on the object being changed inside the for. It can be done by copying the object and iterating over the copy, but the options I mentioned in the answer are much more elegant.

2 answers

11


Answer is somewhat outdated and lacks some additional details. I fixed what was most grotesque and the night I will rewrite it.

You can filter your list of 3 possible ways:

  1. Using the function filter
  2. Using list comprehensions
  3. Using generators

Function filter

In advance of the answer, you can take advantage of the tools that language gives you. How do you want to make a filter on the values of a list, nothing better than using the function filter python:

>>> lista = [2, 3, 1, 5, 1, 7, 8, 8, 9, 15, 1, 1]
>>> lista = list(filter(lambda x: x != 1, lista))
>>> print(lista)
[2, 3, 5, 7, 8, 8, 9, 15]

Filter

Returns an eternal object containing the values of the second parameter whose execution of function on the same return True.

iterable filter(function, iterable)

That is, by doing:

filter(myFilter, lista)

Will be returned all values a generator of lista in which myFilter(x), being x the element of lista, true return. As you want to filter the values equal to 1, just have the condition: x != 1. The function was used lambda due to the simplicity of the function, but nothing stops doing:

>>> lista = [2, 3, 1, 5, 1, 7, 8, 8, 9, 15, 1, 1] 
>>> def is_not_one (value):
...   return value != 1
>>> lista = list(filter(is_not_one, lista))
>>> print(lista)
[2, 3, 5, 7, 8, 8, 9, 15]

The result is exactly the same.

When to use?

The function filter is ideal to be used when filter logic is not so trivial (you can’t write in a line of code).

Basic test:

import random, time, sys

SIZE = 1000000

# Gera-se dados aleatórios entre 0 e 1
lista = [random.randrange(0, 9) for _ in range(SIZE)]

# Filtra a lista através de compressão de listas

START_TIME = time.time()

# Filtra a listra através da função `filter`

list_filter = filter(lambda i: i != 1, lista)

FILTER_TIME = time.time()

print("Execução em: ", FILTER_TIME - START_TIME)
print("Consumo em memória: ", sys.getsizeof(list_filter))

Exit:

Execução em:  5.9604644775390625e-06
Consumo em memória:  56

List Comprehensions

Like answered by the user Camilo Santos:

>>> lista = [2, 3, 1, 5, 1, 7, 8, 8, 9, 15, 1, 1]
>>> lista = [l for l in lista if l != 1]
>>> print(lista) 
[2, 3, 5, 7, 8, 8, 9, 15]

When to use?

It is ideal to use the list comprehensions when the number of elements in the list is small and the filter logic is trivial (which can be written in a row). The new list will be stored completely in memory and, with this, can consume a lot of machine resource if it is too extensive.

Basic test:

import random, time, sys

SIZE = 1000000

# Gera-se dados aleatórios entre 0 e 1
lista = [random.randrange(0, 9) for _ in range(SIZE)]

# Filtra a lista através de compressão de listas

START_TIME = time.time()

list_comprehension = [i for i in lista if i != 1]

LIST_TIME = time.time()

print("Execução em: ", LIST_TIME - START_TIME)
print("Consumo em memória: ", sys.getsizeof(list_comprehension))

Exit:

Execução em:  0.05048513412475586
Consumo em memória:  7731040

Consumes memory and running time, so should be used with caution.


Generator

Using the Python generator tool:

>>> def filter_by_generator(lista, value):
...   for i in lista:
...     if i != value: yield i
>>> lista = filter_by_generator(lista, 1)
>>> print(list(lista))
[2, 3, 5, 7, 8, 8, 9, 15]

When to use?

The generators should be used when the number of items on the list is too large, regardless of how complex the filter logic is (if simple, you can use filter and reduce the code).

Basic test:

import random, time, sys

SIZE = 1000000

# Gera-se dados aleatórios entre 0 e 1
lista = [random.randrange(0, 9) for _ in range(SIZE)]

START_TIME = time.time()

# Filtra a lista através de gerador

def filter_by_generator(lista, value):
  for i in lista:
    if i != value: yield i

lista_generator = filter_by_generator(lista, 1)

GENERATOR_TIME = time.time()

print("Execução em: ", GENERATOR_TIME - START_TIME)
print("Consumo em memória: ", sys.getsizeof(lista_generator))

Exit:

Execução em:  4.291534423828125e-06
Consumo em memória:  88

Both runtime and memory space are much shorter than other methods. This is because the Generator does not compute the entire list at once, but generates each list item in "real time" when it is iterated.

6

Can also be used List Comprehension, it consumes less machine resources than filter() or map(), but the result is exactly the same.

lista = [2, 3, 1, 5, 1, 7, 8, 8, 9, 15, 1, 1]
lista = [l for l in lista if l != 1]
print(lista) #A saída será: [2, 3, 5, 7, 8, 8, 9, 15]

Browser other questions tagged

You are not signed in. Login or sign up in order to post.