Uso de la función filter

La función filter del módulo Enum sirve para extraer de una colección enumerada de elementos una subcolección en la que sólo nos quedamos con aquellos elementos que cumplan con una condición booleana que le indiquemos previamente.

Los tipos enumerados son estructuras de datos que podemos recorrer desde un principio hasta un final, como las listas o los mapas. Por ejemplo, una lista de átomos como [:a, :b, :c, :d] nos permite acceder a cada elemento secuencialmente, ya sea usando funciones como head y tail o mediante funciones que abstraen ese recorrido, como Enum.at, que nos devuelve el elemento en una posición específica sin preocuparnos por la implementación interna.

Los mapas también son tipos enumerados, aunque con una particularidad importante: no garantizan un orden fijo al recorrerlos. Podemos acceder a sus claves y valores, y existen funciones como Map.keys y Map.values que nos devuelven listas con las claves o valores respectivamente. Además, Enum.to_list convierte un mapa en una lista de tuplas, donde cada tupla contiene una clave y su valor asociado. Esto nos permite tratar mapas como colecciones enumerables y aplicarles funciones de alto orden.

Las funciones de alto orden son aquellas que reciben otras funciones como parámetros. En el contexto de tipos enumerados, estas funciones nos permiten procesar colecciones de manera declarativa y concisa. Una de las más útiles es filter, que toma un enumerable y una función que define un criterio, y devuelve una nueva colección con los elementos que cumplen ese criterio.

La función filter funciona aplicando la función criterio a cada elemento del enumerable. Si la función devuelve un valor considerado verdadero, el elemento se incluye en la colección resultante; si devuelve falso, se excluye. Por ejemplo, si tenemos la lista [1, 2, 3, 4, 5] y queremos quedarnos solo con los números pares, podemos usar:

Enum.filter([1, 2, 3, 4, 5], fn x -> rem(x, 2) == 0 end)
# Resultado: [2, 4]

Aquí, la función anónima fn x -> rem(x, 2) == 0 end evalúa si un número es divisible entre 2. filter recorre la lista, aplica esta función a cada elemento y construye una nueva lista con los que cumplen la condición.

Cuando trabajamos con mapas, la función que pasamos a filter recibe cada elemento como una tupla {clave, valor}. Podemos usar pattern matching para extraer solo el valor y aplicar el filtro sobre él. Por ejemplo, dado el mapa %{a: 1, b: 2, c: 3, d: 4}, si queremos quedarnos con las entradas cuyo valor sea par, haríamos:

Enum.filter(%{a: 1, b: 2, c: 3, d: 4}, fn {_k, v} -> rem(v, 2) == 0 end)
# Resultado: [b: 2, d: 4]

Es importante notar que el resultado no es un mapa, sino una Keyword List con las tuplas que cumplen el criterio.

La ventaja principal de usar filter y otras funciones de alto orden frente a los bucles tradicionales es que delegamos en el lenguaje la gestión del recorrido y la construcción de la colección resultante. En lenguajes imperativos como C o Java, tendríamos que escribir explícitamente un bucle, una condición y una estructura para almacenar los resultados, lo que implica más código y mayor complejidad, especialmente si queremos optimizar el procesamiento o paralelizarlo.

Con filter, simplemente definimos qué queremos filtrar y dejamos que la función se encargue del resto. Esto no solo hace el código más legible y conciso, sino que también abre la puerta a optimizaciones internas que el lenguaje pueda aplicar, como procesamiento paralelo o evaluaciones perezosas, sin que tengamos que preocuparnos por esos detalles.

Entender bien cómo funciona filter es fundamental antes de avanzar a otras funciones de alto orden como map o reduce, que también nos permiten transformar y combinar colecciones de manera elegante y eficiente.

Lista de reproducción
  1. 1
    ¿Qué es Elixir?
    10 minutos
  2. 2
    Instalación de Elixir
    9 minutos
  3. 3
    ¿Qué es la programación funcional? (Como la de Elixir)
    20 minutos
  4. 4
    ¿Cómo funciona la REPL de Elixir?
    7 minutos
  5. 5
    ¿Cómo hacer asignaciones en Elixir?
    7 minutos
  6. 6
    Operadores aritméticos básicos
    6 minutos
  7. 7
    ¿Qué son los tipos de datos de Elixir?
    5 minutos
  8. 8
    Átomos en Elixir
    4 minutos
  9. 9
    Las palabras clave nil, true y false
    6 minutos
  10. 10
    Operadores lógicos de comparación
    8 minutos
  11. 11
    Comparación estricta con ===
    3 minutos
  12. 12
    Operadores lógicos y proposicionales
    8 minutos
  13. 13
    Invocación de funciones
    10 minutos
  14. 14
    Fundamentos de funciones
    9 minutos
  15. 15
    Cadenas de caracteres
    8 minutos
  16. 16
    Entrada y salida estandar de la mano de gets y puts
    9 minutos
  17. 17
    Concatenar e interpolar strings
    9 minutos
  18. 18
    Código fuente en archivos
    9 minutos
  19. 19
    Condicional IF y bloques DO-END
    11 minutos
  20. 20
    IFs anidados, UNLESS y COND
    12 minutos
  21. 21
    Definición de funciones
    11 minutos
  22. 22
    Fundamentos de compilación de módulos
    6 minutos
  23. 23
    Guardas
    8 minutos
  24. 24
    Funciones anónimas
    7 minutos
  25. 25
    Capturar funciones
    4 minutos
  26. 26
    Invocación de funciones dentro del mismo módulo
    7 minutos
  27. 27
    Tuplas
    8 minutos
  28. 28
    Introducción al pattern matching
    8 minutos
  29. 29
    Pattern matching en funciones
    11 minutos
  30. 30
    Las tuplas :ok, :error
    7 minutos
  31. 31
    case
    10 minutos
  32. 32
    Operador pin
    7 minutos
  33. 33
    Pattern matchings y recursividad
    5 minutos
  34. 34
    Listas
    9 minutos
  35. 35
    Operadores y funciones de lista
    10 minutos
  36. 36
    Keyword lists: listas de palabras clave
    8 minutos
  37. 37
    Mapas
    7 minutos
  38. 38
    Pattern matching de mapas y keyword lists
    6 minutos
  39. 39
    Operadores y funciones para mapas y keyword lists
    5 minutos
  40. 40
    Estructuras con defstruct
    11 minutos
  41. 41
    Bitstrings
    11 minutos
  42. 42
    Charlists
    10 minutos
  43. 43
    Funciones de alto orden en Elixir
    5 minutos
  44. 44
    Uso de la función filter
    10 minutos
  45. 45
    Uso de la función map
    7 minutos
  46. 46
    Uso de la función reduce
    9 minutos
  47. 47
    Pipelines
    11 minutos
  48. 48
    Rangos y Streams
    11 minutos
  49. 49
    Funciones recursivas con listas
    14 minutos