Como usar a função de filtro do Python

Introdução

A função integrada filter() do Python pode ser usada para criar um novo iterador a partir de um iterável existente (como uma list a ou um dicionário) que irá filtrar de forma eficiente os elementos usando uma função que fornecemos. Um iterável é um objeto do Python que pode “sofrer iteração”, ou seja, ele retornará itens em uma sequência para que possamos usá-la em um loop for.

A sintaxe básica para a função filter() é:

filter(function, iterable) 

Isso irá retornar um objeto de filtro, que é um iterável. Podemos usar uma função como a list() para fazer uma lista de todos os itens retornados em um objeto de filtro.

A função filter() fornece uma forma de filtrar valores que muitas vezes pode ser mais eficiente do que uma compreensão de lista, especialmente quando começamos a trabalhar com conjuntos de dados maiores. Por exemplo, uma compreensão de lista fará uma nova lista, que irá aumentar o tempo de execução para esse processamento. Isso significa que depois que nossa compreensão de lista tiver completado a expressão, teremos duas listas na memória. Por outro lado, a função filter() fará um objeto simples que contém uma referência à lista original, a função fornecida e um índice de onde ir na lista original, que irá ocupar menos memória.

Neste tutorial, vamos revisar quatro maneiras diferentes de usar a filter(): com duas estruturas iteráveis diferentes, com uma função lambda e sem uma função definida.

Como usar filter() com uma função

O primeiro argumento para filter() é uma função, que usamos para decidir se é preciso incluir ou filtrar cada item. A função é chamada uma vez para cada item presente no iterável passado como segundo argumento e, cada vez que ela retorna False, o valor é abandonado. Como este argumento é uma função, podemos passar uma função normal ou fazer uso das funções lambda, especialmente quando a expressão for menos complexa.

A seguir, está a sintaxe de uma lambda com filter():

filter(lambda item: item[] expression, iterable) 

Em uma lista, como a seguinte, podemos incorporar uma função lambda com uma expressão sobre a qual queremos avaliar cada item da lista:

creature_names = ['Sammy', 'Ashley', 'Jo', 'Olly', 'Jackie', 'Charlie'] 

Para filtrar esta lista de forma a encontrar os nomes das nossas criaturas de aquário que começam com uma vogal, podemos executar a seguinte função lambda:

print(list(filter(lambda x: x[0].lower() in 'aeiou', creature_names))) 

Aqui declaramos um item em nossa lista como x. Então, definimos nossa expressão para acessar o primeiro caractere de cada string (ou o caractere “zero”), que é x[0]. Deixar a primeira letra minúscula em cada um dos nomes garante que eles terão letras correspondentes com a string em nossa expressão, 'aeiou'.

Por fim, passamos o iterável creature_names. Assim como na seção anterior, aplicamos list() ao resultado para criar uma lista a partir dos retornos do filter() iterador.

O resultado será o seguinte:

Output['Ashley', 'Olly'] 

Este mesmo resultado pode ser alcançado usando uma função que definimos:

creature_names = ['Sammy', 'Ashley', 'Jo', 'Olly', 'Jackie', 'Charlie']  def names_vowels(x):   return x[0].lower() in 'aeiou'  filtered_names = filter(names_vowels, creature_names)  print(list(filtered_names)) 

Nossa função names_vowels define a expressão que implementaremos para filtrar creature_names.

Mais uma vez, o resultado seria o seguinte:

Output['Ashley', 'Olly'] 

De modo geral, as funções lambda alcançam o mesmo resultado com filter() se comparadas a quando usamos uma função regular. A necessidade de definir uma função regular cresce à medida que a complexidade das expressões que filtram nossos dados aumenta e é provável que isso promova uma maior legibilidade em nosso código.

Como usar None com filter()

Podemos passar None como o primeiro argumento para filter() para que o iterador retornado filtre qualquer valor que o Python considere “aparentemente falso”. No geral, o Python considera qualquer coisa com um comprimento 0 (como uma lista vazia ou uma string vazia) ou numericamente equivalente a 0 como falso, por isso o uso do termo “aparentemente falso”.

No caso a seguir, queremos filtrar nossa lista para mostrar apenas os números de tanques em nosso aquário:

aquarium_tanks = [11, False, 18, 21, "", 12, 34, 0, [], {}] 

Neste código, temos uma lista que contém inteiros, sequências vazias e um valor booleano.

filtered_tanks = filter(None, aquarium_tanks) 

Usamos a função filter() com None e inserimos a lista aquarium_tanks como nosso iterável. Como passamos o None como o primeiro argumento, vamos verificar se os itens em nossa lista são considerados falsos.

print(list(filtered_tanks)) 

Então, nós colocamos filtered_tanks em uma função list() para que ela retorne uma lista para filtered_tanks quando imprimirmos.

Aqui vemos que o resultado mostra apenas os inteiros. Todos os itens que foram avaliados como False, que equivalem a 0 de comprimento, foram removidos por filter():

Output[11, 25, 18, 21, 12, 34] 

Nota: se não usarmos list() e imprimirmos filtered_tanks receberíamos um objeto de filtro parecido com este: <filter object at 0x7fafd5903240>. O objeto de filtro é um iterável, então poderíamos aplicar um loop sobre ele com for ou podemos usar o list() para transformá-lo em uma lista, que é o que estamos fazendo aqui porque é uma boa maneira de revisar os resultados.

Com o None, usamos filter() para remover itens de nossa lista que foram considerados falsos.

Como usar filter() com uma lista de dicionários

Quando temos uma estrutura de dados mais complexa, ainda podemos usar filter() para avaliar cada um dos itens. Por exemplo, se tivermos uma lista de dicionários, não só queremos iterar sobre cada item na lista — um dos dicionários — mas também podemos querer iterar sobre cada par de chave:valor em um dicionário para avaliar todos os dados.

Como um exemplo, vamos considerar que temos uma lista de cada criatura em nosso aquário, juntamente com detalhes específicos sobre cada uma delas:

aquarium_creatures = [   {"name": "sammy", "species": "shark", "tank number": "11", "type": "fish"},   {"name": "ashley", "species": "crab", "tank number": "25", "type": "shellfish"},   {"name": "jo", "species": "guppy", "tank number": "18", "type": "fish"},   {"name": "jackie", "species": "lobster", "tank number": "21", "type": "shellfish"},   {"name": "charlie", "species": "clownfish", "tank number": "12", "type": "fish"},   {"name": "olly", "species": "green turtle", "tank number": "34", "type": "turtle"} ] 

Queremos filtrar esses dados por uma string de pesquisa que damos à função. Para que filter() acesse cada dicionário e cada item nos dicionários, construímos uma função aninhada, como a seguinte:

def filter_set(aquarium_creatures, search_string):     def iterator_func(x):         for v in x.values():             if search_string in v:                 return True         return False     return filter(iterator_func, aquarium_creatures) 

Definimos uma função filter_set() que recebe aquarium_creatures e search_string como parâmetros. Em filter_set(), passamos nossa iterator_func() como a função para filter(). A função filter_set() irá retornar o iterador resultante de filter().

A iterator_func() recebe x como um argumento, que representa um item em nossa lista (ou seja, um único dicionário).

Em seguida, o loop for acessa os valores em cada par chave:valor em nossos dicionários e então usa uma declaração condicional para verificar se o search_string está em v, representando um valor.

Assim como em nossos exemplos anteriores, se a expressão for avaliada como True, a função adiciona o item ao objeto de filtro. Isso será retornado depois que a função filter_set() tiver sido concluída. Posicionamos return False fora do nosso loop para que ele verifique todos os itens em cada dicionário, em vez de retornar depois de verificar somente o primeiro dicionário.

Chamamos filter_set() com nossa lista de dicionários e a string de pesquisa para a qual queremos encontrar correspondências:

filtered_records = filter_set(aquarium_creatures, "2")     

Assim que a função tiver sido concluída, temos nosso objeto de filtro armazenado na variável filtered_records, que transformamos em uma lista e imprimimos:

print(list(filtered_records))       

Veremos o seguinte resultado a partir deste programa:

Output[{'name': 'ashley', 'species': 'crab', 'tank number': '25', 'type': 'shellfish'}, {'name': 'jackie', 'species': 'lobster', 'tank number': '21', 'type': 'shellfish'}, {'name': 'charlie', 'species': 'clownfish', 'tank number': '12', 'type': 'fish'}] 

Filtramos a lista de dicionários com a string de pesquisa 2. Podemos ver que os três dicionários que incluíam um número de tanque com 2 foram retornados. Usar nossa própria função aninhada nos permitiu acessar todos os itens e comparar eficientemente cada um com a string de busca.

Conclusão

Neste tutorial, aprendemos as diferentes formas de usar a função filter() em Python. Agora, você é capaz de usar filter() com sua própria função, uma função lambda, ou com None para a filtragem, sendo capaz de lidar com itens de complexidades e em estruturas de dados diferentes.

Embora neste tutorial tenhamos imprimido os resultados de filter() imediatamente em formato de lista, é provável que em nossos programas usemos o objeto filter() retornado e manipulemos ainda mais os dados.

Se você quiser aprender mais sobre Python, confira nossa série Como programar em Python 3 e nossa página do tópico Python.