Archivador con fichas ordenadas y etiquetadas junto a una lista numerada en papel, como metáfora de diccionarios y listas

Listas y diccionarios: estructuras de datos para empezar

· ⏱ 8+ min lectura

Cuando una variable no basta

Llevamos toda la serie de Fundamentos de programación guardando datos en variables. Pero una variable guarda una sola cosa: un número, un texto, un sí o un no. Y el mundo real casi nunca va de una sola cosa.

La lista de la compra tiene veinte productos. Una tienda tiene mil artículos. Un usuario tiene nombre, email, edad y dirección, todo junto. Si tuvieras que crear una variable suelta para cada elemento (producto1, producto2, producto3…) sería una locura, y además, ¿cómo los recorres con un bucle? Para esto existen las estructuras de datos: formas de guardar muchos valores juntos y organizados. Hoy vemos las dos imprescindibles.

La lista (array): una colección ordenada

Una lista (también llamada array o vector) es una colección ordenada de elementos guardados bajo un solo nombre. Es como una fila de cajas numeradas, una detrás de otra:

compra = ["pan", "leche", "huevos", "café"]

Esa única variable, compra, contiene cuatro elementos en un orden concreto. Y a cada uno accedes por su posición, lo que se llama el índice:

mostrar compra[0]    // "pan"
mostrar compra[2]    // "huevos"

El detalle que pilla a todos: se empieza en cero

Para. Lee otra vez. compra[0] es “pan”, el primer elemento. No compra[1].

Esto es lo que más confunde al empezar, y conviene grabárselo a fuego: en programación, las listas casi siempre empiezan a contar en cero. El primer elemento es el índice 0, el segundo es el 1, el tercero es el 2… Así que en una lista de 4 elementos, los índices van del 0 al 3. ¿El último? El 3, no el 4.

¿Por qué esta rareza? Por motivos históricos y técnicos (el índice representa “cuánto te desplazas desde el principio”). No le des más vueltas: es así, lo aceptas y ya. Pero te aviso de un error clásico que vas a cometer, todos lo cometemos: pedir compra[4] en una lista de 4 elementos. No existe el índice 4. Eso se llama “índice fuera de rango” y es de los fallos más frecuentes del mundo.

Operar con listas: recorrer, añadir, quitar

Las listas se manejan constantemente, y casi siempre haces lo mismo con ellas.

Recorrerlas con un bucle, normalmente con el for-each que vimos:

PARA CADA producto EN compra
  mostrar producto
FIN PARA CADA

Añadir un elemento al final (la operación típica es añadir o push):

compra.añadir("aceite")    // ahora hay 5 elementos

Quitar un elemento, por posición o por valor. Y casi todos los lenguajes te dan más herramientas: saber cuántos elementos hay (la longitud o length), comprobar si un elemento está en la lista, ordenarla, darle la vuelta. Con recorrer, añadir, quitar y contar te defiendes en el 90% de los casos.

El diccionario (mapa): pares de clave y valor

La lista va genial cuando el orden y la posición importan. Pero a veces no quieres acceder por “el tercero”, sino por nombre. ¿Cuál es el email de Marcos? ¿Cuál es el precio del producto “SKU-200”? Para eso está el diccionario (también mapa, map, hash u objeto, según el lenguaje).

Un diccionario guarda pares de clave y valor. La clave es la etiqueta por la que buscas; el valor, lo que hay guardado bajo esa etiqueta:

usuario = {
  "nombre": "Marcos",
  "email": "marcos@correo.com",
  "edad": 35
}

mostrar usuario["email"]    // "marcos@correo.com"

Aquí no accedes por posición ([0], [1]), accedes por clave (["email"]). Es como una agenda: no buscas “el contacto número 47”, buscas “el teléfono de Marcos”. Por eso el diccionario es perfecto para representar cosas con propiedades: un usuario, un producto, una configuración.

Lista o diccionario: cuándo cada uno

La pregunta que te harás mil veces. La regla rápida:

  • Lista cuando tienes muchos elementos del mismo tipo y el orden importa, o accedes por posición. La compra, los mensajes de un chat, las filas de una tabla.
  • Diccionario cuando tienes una cosa con propiedades con nombre, y accedes por etiqueta. Un usuario, un producto, los ajustes de una app.

Y muy a menudo se combinan: una lista de diccionarios es, posiblemente, la estructura más común del mundo real. Por ejemplo, todos los usuarios de una web:

usuarios = [
  { "nombre": "Marcos", "edad": 35 },
  { "nombre": "Lucia", "edad": 31 }
]

mostrar usuarios[0]["nombre"]    // "Marcos"

Una lista por fuera, diccionarios dentro. Si entiendes esto, entiendes el formato JSON, que es exactamente esto y mueve hoy media internet.

Dos primas: conjuntos y tuplas

Para que las conozcas de oídas, hay dos estructuras más que aparecen menos pero conviene reconocer:

  • Conjunto (set): como una lista, pero sin elementos repetidos y normalmente sin orden. Útil justo para eso, garantizar que no hay duplicados, o comprobar muy rápido si algo “pertenece” al conjunto.
  • Tupla (tuple): como una lista, pero fija: una vez creada no se puede cambiar. Útil para grupos pequeños de valores que van juntos y no deben tocarse, como unas coordenadas (x, y).

No te obsesiones con ellas ahora. Con listas y diccionarios dominados, tienes ganado el grueso del trabajo diario.

El puente: las estructuras avanzadas

Listas y diccionarios son las estructuras básicas, las del día a día. Pero hay todo un mundo de estructuras avanzadas, diseñadas para resolver problemas concretos de forma eficiente: pilas, colas, listas enlazadas, tablas hash, árboles, grafos. Cada una tiene su superpoder y su momento.

Esas no son de esta serie. Son el corazón de la serie de Algoritmos, donde se ve por qué importan y cuándo usar cada una. Por ahora, quédate con que existen y que se construyen, en el fondo, combinando las ideas que has aprendido aquí.

Lo siguiente: cuando todo se rompe

Ya tienes prácticamente todas las piezas: variables, operadores, condicionales, bucles, funciones y estructuras de datos. Con esto puedes escribir programas completos. Y entonces descubrirás la otra cara de programar: que se rompe. Todo el rato.

La última entrega de la serie va justo de eso, y es de las más útiles de todas: los errores y la depuración. Tipos de error, leer un mensaje de fallo sin entrar en pánico y cazar bugs como un detective. Porque programar es, más que nada, arreglar lo que no funciona.

Preguntas frecuentes

¿Por qué las listas empiezan a contar en cero?

Por motivos históricos y técnicos: el índice representa el desplazamiento desde el principio de la lista, y el primer elemento está a desplazamiento cero. Por eso el primer elemento es el índice 0, el segundo el 1, y en una lista de 4 elementos los índices válidos van del 0 al 3. Pedir el índice 4 en esa lista provoca el clásico error de “índice fuera de rango”.

¿Cuándo uso una lista y cuándo un diccionario?

Usa una lista cuando tienes muchos elementos del mismo tipo y el orden o la posición importan: la lista de la compra, los mensajes de un chat. Usa un diccionario cuando representas una cosa con propiedades con nombre y accedes por etiqueta en lugar de por posición: un usuario con nombre, email y edad. Muchas veces se combinan, como una lista de diccionarios.

¿Qué diferencia hay entre una lista y un conjunto?

Una lista mantiene el orden y permite elementos repetidos: puedes tener “pan” dos veces. Un conjunto (set) no permite duplicados y normalmente no garantiza un orden concreto. Se usa un conjunto cuando lo que te importa es que no haya elementos repetidos o comprobar muy rápido si un valor pertenece o no a la colección.

El libro para esta entrega

Las estructuras de datos son el puente natural hacia los algoritmos, y para eso no hay nada como Comprender los algoritmos, de Aditya Bhargava. Explica listas, diccionarios, tablas hash y demás con dibujos y sentido común, sin matemáticas asustaviejas. Es el libro perfecto para preparar la siguiente serie.

Este artículo contiene enlaces de afiliado.

Compártelo si te ha resultado útil.

¿Te acuerdas de la primera vez que pediste el elemento que no existía por contar desde el uno? Cuéntame tu pelea con el índice cero.

Y… en la próxima entrega cerramos la serie arreglando lo que se rompe.

Artículos relacionados

Cafetera espresso con granos de café entrando por arriba y una taza de café saliendo por el surtidor, como metáfora de una función que recibe datos y devuelve un resultado

Las funciones en programación: parámetros, retorno y scope

Cuando llevas un rato programando notas que repites los mismos trozos de código por todas partes, y eso es justo lo que no hay que hacer. La solución son las funciones: empaquetar un trozo de programa, ponerle nombre y reutilizarlo siempre que quieras. En esta sexta entrega de la serie de Fundamentos te explico cómo se define y se llama una función, la diferencia entre parámetros y argumentos, qué es el valor de retorno, el concepto de ámbito (scope) local y global, la diferencia entre pasar datos por valor y por referencia, qué son los efectos secundarios, y el principio DRY que resume por qué todo esto importa. También asomamos la recursión, que veremos a fondo en la serie de Algoritmos.

16:00 8 min Marcos Ramírez Lucía
Vista aérea de una rotonda al anochecer con las estelas de luz de los coches formando un círculo continuo, como metáfora de un bucle

Bucles en programación: for, while y do-while desde cero

Si tuvieras que saludar a cien usuarios, ¿escribirías cien veces la misma línea? Claro que no. Para repetir trabajo sin copiar y pegar existen los bucles, y son una de las herramientas que más usarás en tu vida programando. En esta quinta entrega de la serie de Fundamentos te explico los tres bucles básicos (for, while y do-while), cuándo usar cada uno, el for-each para recorrer colecciones cómodamente, el break y el continue para controlar la repetición por dentro, y el clásico susto del principiante: el bucle infinito que cuelga el programa, por qué ocurre y cómo evitarlo. Todo con pseudocódigo y ejemplos cortos para que lo veas claro.

16:00 8 min Marcos Ramírez Lucía
Bifurcación de un camino en dos direcciones señalizadas, vista cenital, como metáfora de una decisión en un programa

Condicionales en programación: if, else y switch desde cero

Hasta ahora nuestros programas iban en línea recta, una instrucción detrás de otra. Pero un programa útil tiene que decidir: hacer una cosa si se cumple algo y otra distinta si no. De eso van los condicionales, y son lo que de verdad le da inteligencia a tu código. En esta cuarta entrega de la serie de Fundamentos te explico el if, el else y el else if, el switch para cuando hay muchos caminos, el operador ternario como condicional exprés, cómo combinar varias condiciones, el peligro de anidar demasiado y un truco que te cambiará la vida: las guard clauses (cláusulas de guarda) para escribir condicionales que se leen sin marearte. Todo con pseudocódigo y ejemplos cortos.

16:00 8 min Marcos Ramírez Lucía