Listas

Las listas son una estructura de datos que en Elixir permite agrupar de forma dinámica múltiples elementos. A diferencia de las tuplas, tienen una estructura diferente compuesta de cabeza y cola, lo cual nos puede dar juego en algunos casos, pero sin olvidarnos de sus consecuencias.

Las listas enlazadas en Elixir son una estructura fundamental que, aunque sencilla, tiene particularidades que vale la pena entender bien para aprovecharlas al máximo. A diferencia de las tuplas, que almacenan sus elementos de forma contigua en memoria, las listas enlazadas funcionan mediante una composición de cabeza y cola, lo que las hace especialmente útiles para ciertas operaciones y para el pattern matching.

Cuando hablamos de listas en Elixir, visualmente las vemos como una secuencia de elementos entre corchetes, por ejemplo [1, 2, 3, 4]. Sin embargo, internamente, esta lista no es simplemente un bloque de memoria con esos cuatro valores uno tras otro, sino que está formada por una cabeza y una cola. La cabeza es el primer elemento de la lista, en este caso 1, y la cola es el resto de la lista, es decir, [2, 3, 4].

Podemos obtener la cabeza de una lista usando la función hd, que nos devuelve el primer elemento, y la cola con la función tl, que nos devuelve el resto de la lista sin la cabeza. Por ejemplo, hd([1, 2, 3, 4]) nos da 1, y tl([1, 2, 3, 4]) nos da [2, 3, 4].

Esta estructura se repite recursivamente: la cola es a su vez otra lista con su propia cabeza y cola. Así, la cola [2, 3, 4] tiene cabeza 2 y cola [3, 4], y así sucesivamente hasta llegar a la lista vacía [], que es un caso especial que no tiene cabeza ni cola.

En Elixir, podemos construir listas explícitamente usando esta idea de cabeza y cola con la sintaxis [cabeza | cola]. Por ejemplo, si definimos:

base = []
uno = [1 | base]
dos = [2 | uno]
tres = [3 | dos]
cuatro = [4 | tres]

Aquí, uno es la lista [1], dos es [2, 1], tres es [3, 2, 1] y cuatro es [4, 3, 2, 1]. Esta forma de construir listas nos permite entender cómo se enlazan los elementos internamente.

El pattern matching con listas enlazadas es muy potente. Podemos extraer la cabeza y la cola de una lista directamente en una asignación, por ejemplo:

[cabeza | cola] = [1, 2, 3, 4, 5]
# cabeza = 1
# cola = [2, 3, 4, 5]

Además, podemos hacer pattern matching con varios elementos al principio y luego la cola, así:

[one, two | resto] = [1, 2, 3, 4, 5]
# one = 1
# two = 2
# resto = [3, 4, 5]

Es importante recordar que la barra vertical | siempre debe ir a la izquierda en la sintaxis de pattern matching para listas. No es válido poner la barra a la derecha de las comas, ya que la parte después de la barra representa la cola, que debe ser una lista.

También debemos tener cuidado con el número de elementos cuando hacemos pattern matching con comas. Si intentamos hacer coincidir un número fijo de elementos con variables y la lista no tiene exactamente ese número, obtendremos un error. Por eso, cuando no sabemos el tamaño exacto, es mejor usar la barra para capturar la cola restante.

Por ejemplo, esto es válido:

[head | tail] = [1, 2, 3]
# head = 1
# tail = [2, 3]

Pero esto puede fallar si la lista no tiene el número exacto de elementos:

[a, b, c] = [1, 2]
# Error: no hay suficientes elementos para hacer match

En resumen, las listas enlazadas en Elixir se basan en la idea de cabeza y cola, lo que facilita su manipulación mediante pattern matching y permite construir listas de forma recursiva y elegante. Esta estructura es diferente a las tuplas, que son bloques contiguos en memoria, y entender esta diferencia nos ayuda a escribir código más claro y eficiente en Elixir.

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