Cómo usar la función de filtro en Python

Introducción

La función filter() integrada de Python puede usarse para crear un nuevo iterador a partir de un iterable existente (como una lista o un diccionario) que filtrará de forma eficiente los elementos usando una función que proporcionamos. Un iterable es un objeto Python que puede “repetirse” es decir, devolverá elementos en una secuencia de forma que podamos usarla en un bucle for.

La sintaxis básica para la función filter() es:

filter(function, iterable) 

Esto devolverá un objetivo de filtro, que es un iterable. Podemos usar una función como list() para hacer una lista de todos los elementos devueltos en un objeto de filtro.

La función filter() proporciona una forma de filtrar valores que a menudo pueden ser más eficientes que un list comprehension, especialmente cuando comenzamos a trabajar con conjuntos de datos más grandes. Por ejemplo, un list comprehension creará una nueva lista, que aumentará el tiempo de ejecución para ese procesamiento. Esto significa que una vez que nuestro list comprehension haya completado su expresión, tendremos dos listas en la memoria. Sin embargo, filter() creará un objeto simple que alberga una referencia a la lista original, la función proporcionada y un índice de dónde ir en la lista original, lo que ocupa menos memoria.

En este tutorial, revisaremos cuatro formas diferentes de usar filter(): con dos estructuras iterables diferentes, con una función lambda y sin función definida.

Usar filter() con una función

El primer argumento para filter() es una función, que usamos para decidir si incluir o filtrar cada elemento. La función se invoca una vez para cada elemento en el iterable pasado como segundo argumento y cada vez que devuelve False, se suelta el valor. Ya que este argumento es una función, podemos pasar una función normal o podemos usar las funciones lambda, sobre todo cuando la expresión es menos compleja.

A continuación, está la sintaxis de un lambda con filter():

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

Con una lista, como la siguiente, podemos incorporar una función lambda con una expresión contra la cual queremos evaluar cada elemento de la lista:

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

Para filtrar esta lista para encontrar los nombres de nuestras criaturas de acuario que comienzan con vocal, podemos ejecutar la siguiente función lambda:

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

Aquí declaramos un elemento en nuestra lista como x. Luego establecemos nuestra expresión para acceder al primer carácter de cada cadena (o carácter “cero”, de forma que x[0]. Reduciendo la capitalización de cada nombre garantiza que esto hará coincidir las letras con la cadena en nuestra expresión "aeiou".

Finalmente, pasamos el iterable creature_names. Al igual que la sección anterior, aplicamos list() al resultado para crear una lista desde el iterador filter() que devuelve.

El resultado será el siguiente:

Output['Ashley', 'Olly'] 

Este mismo resultado puede conseguirse usando una función que definamos:

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)) 

Nuestra función names_vowels define la expresión que implementaremos para filtrar creature_names.

De nuevo, el resultado será el siguiente:

Output['Ashley', 'Olly'] 

En general, las funciones lambda consiguen el mismo resultado con filter() que cuando usamos una función regular. La necesidad de definir una función regular aumenta a medida que la complejidad de las expresiones para filtrar nuestros datos se incrementa, lo que probablemente promueva una mejor legibilidad de nuestro código.

Usar None con filter()

Podemos pasar None como el primer argumento para que filter() tenga el filtro iterador devuelto de cualquier valor que Python considere falso. Generalmente, Python considera cualquier cosa con una longitud de 0 (como una lista vacía o una cadena vacía) o numéricamente equivalente a 0 como falso, por tanto el uso del término “falso”.

En el siguiente caso, queremos filtrar nuestra lista para que solo muestre los números de tanques en nuestro acuario:

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

En este código tenemos una lista que contiene enteros, secuencias vacías y un valor boleano.

filtered_tanks = filter(None, aquarium_tanks) 

Usamos la función filter() con None y pasamos la lista aquarium_tanks como nuestro iterable. Ya que hemos pasado None como el primer argumento, comprobaremos si los elementos de nuestra lista se consideran falsos.

print(list(filtered_tanks)) 

Luego envolvemos filtered_tanks en una función list() de forma que devuelva una lista para filtered_tanks cuando imprimamos.

Aquí vemos que el resultado muestra solo los enteros. Todos los elementos que evaluaron a False, que son equivalentes a 0 en longitud, han sido eliminados por filter():

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

Nota: Si no usamos list() e imprimimos filtered_tanks, recibiríamos un objeto de filtro similar a este: <filter object at 0x7fafd5903240>. El objeto de filtro es un iterable, de forma que podríamos hacer un bucle sobre él con for o podemos usar list() para convertirlo en una lista, lo que haremos aquí porque es una buena forma de revisar los resultados.

Con None hemos usado filter() para eliminar rápidamente elementos de nuestra lista que se consideraban falsos.

Usar filter() con una Lista de diccionarios

Cuando tengamos una estructura de datos más compleja, aún podemos usar filter() para evaluar cada uno de los elementos. Por ejemplo, si tenemos una lista de diccionarios, no solo queremos iterar sobre cada elemento en la lista, uno de los diccionarios, sino que también queremos iterar sobre cada par key:value en un diccionario para evaluar todos los datos.

Como ejemplo, digamos que tenemos una lista de cada criatura en nuestro acuario junto con detalles diferentes sobre cada una de ellas:

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 estos datos mediante una cadena de búsqueda que damos a la función. Para que filter() acceda a cada diccionario y a cada elemento en los diccionarios, construimos una función anidada, como la siguiente:

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 una función filter_set() que toma aquarium_creatures y search_string como parámetros. En filter_set(), pasamos nuestra iterator_func() como la función para filter(). La función filter_set() devolverá el iterador resultante de filter().

iterator_func() toma x como argumento, lo que representa un elemento en nuestra lista (es decir, un único diccionario).

A continuación, el bucle for accede a los valores en cada par key:value en nuestros diccionarios, y luego utiliza una instrucción condicional para coprobar si search_string está en v, representando un valor.

Igual que en nuestros ejemplos anteriores, si la expresión evalúa a True, la función añade el elemento al objeto de filtro. Esto devolverá una vez la función filter_set() que ha completado. Posicionamos return False fuera de nuestro bucle para que compruebe cada elemento en cada diccionario, en vez de devolver tras comprobar solo el primer diccionario.

Invocamos filter_set() con nuestra lista de diccionarios y la cadena de búsqueda para la que queremos encontrar coincidencias:

filtered_records = filter_set(aquarium_creatures, "2")     

Una vez que la función se complete, tenemos nuestro objeto de filtro almacenado en la variable filtered_records, que convertimos en una lista e imprimimos:

print(list(filtered_records))       

Veremos el siguiente resultado de este 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'}] 

Hemos filtrado la lista de diccionarios con la cadena de búsqueda 2. Podemos ver que los tres diccionarios que incluyen un número de tanque con 2 han sido devueltos. Usar nuestra función anidada nos ha permitido acceder a cada elemento y comprobar de forma eficiente en comparación con la cadena de búsqueda.

Conclusión

En este tutorial, hemos aprendido las diferentes formas de usar la función filter() en Python. Ahora puede usar filter() con su propia función, una función lambda, o con None para filtrar elementos en estructuras de datos de diferentes complejidades.

Aunque en este tutorial imprimimos los resultados de filter() inmediatamente en un formato de lista, es probable que en nuestros programas usemos el objeto filter() devuelto y manipulemos aún más los datos.

Si desea aprender más sobre Python, consulte nuestra serie Cómo crear código en Python 3 y en nuestra página de tema Python.