Ir al contenido

HashMap en Rust

Un HashMap (mapa hash) guarda datos como pares clave-valor: buscas las cosas por una clave, en lugar de por su posición como harías con un array o un vector. Si has usado un diccionario en Python o un objeto como mapa en JavaScript, es la misma idea.

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alicia", 30);
ages.insert("Bob", 25);
println!("{:?}", ages);
}

La línea use std::collections::HashMap; del principio trae el tipo al ámbito. A diferencia de Vec y String, HashMap no está disponible por defecto, así que esta línea es obligatoria.

▶ Pruébalo tú mismo
use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alicia", 30);
match ages.get("Alicia") {
Some(age) => println!("Alicia tiene {age} años"),
None => println!("No encontrada"),
}
}
▶ Pruébalo tú mismo

.get() devuelve un Option en lugar del valor directamente, porque puede que la clave no exista. Veremos Option a fondo en su propia página; por ahora, un match con Some/None es la forma habitual de manejarlo.

Si vuelves a insertar con la misma clave, se sobrescribe el valor anterior:

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alicia", 30);
ages.insert("Alicia", 31); // sobrescribe el 30
println!("{:?}", ages.get("Alicia"));
}
▶ Pruébalo tú mismo

Si solo quieres insertar un valor cuando la clave todavía no existe, usa .entry():

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alicia", 30);
ages.entry("Alicia").or_insert(99); // Alicia ya existe, así que no hace nada
ages.entry("Bob").or_insert(25); // Bob no existe, así que lo inserta
println!("{:?}", ages);
}
▶ Pruébalo tú mismo
use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alicia", 30);
ages.insert("Bob", 25);
for (name, age) in &ages {
println!("{name} tiene {age} años");
}
}
▶ Pruébalo tú mismo

Usa un HashMap siempre que quieras buscar cosas por un nombre o un ID en lugar de por su posición: contar cuántas veces aparece cada palabra, relacionar nombres de usuario con sus datos, guardar resultados en caché por clave. Si el orden importa o simplemente estás recorriendo una lista, un Vec encaja mejor.

Guarda tres nombres con sus números de teléfono en un HashMap. Después, busca a "Ben" (que sí está) y a "Dana" (que no está), e imprime una línea amable para cada uno. Pista: recorre ["Ben", "Dana"] y haz match sobre .get(name).

Ver solución
use std::collections::HashMap;
fn main() {
let mut phone_book = HashMap::new();
phone_book.insert("Ana", "555-1234");
phone_book.insert("Ben", "555-9876");
phone_book.insert("Chen", "555-4321");
for name in ["Ben", "Dana"] {
match phone_book.get(name) {
Some(number) => println!("{name}: {number}"),
None => println!("{name}: no está en la agenda"),
}
}
}

Salida:

Ben: 555-9876
Dana: no está en la agenda
▶ Pruébalo tú mismo

Recorrer los nombres que nos interesan, en lugar del propio mapa, también nos da un orden fijo. Es un truco práctico siempre que necesites una salida predecible de un HashMap.

Tienes los votos ["rojo", "azul", "rojo", "verde", "azul", "rojo"]. Cuenta cuántos recibió cada color e imprime los totales de "rojo", "verde", "azul" y "rosa" (que no recibió ninguno). Pista: counts.entry(color).or_insert(0) te da el conteo actual de ese color, empezando en 0. Súmale uno con *count += 1.

Ver solución
use std::collections::HashMap;
fn main() {
let votes = ["rojo", "azul", "rojo", "verde", "azul", "rojo"];
let mut counts = HashMap::new();
for color in votes {
let count = counts.entry(color).or_insert(0);
*count += 1;
}
for color in ["rojo", "verde", "azul", "rosa"] {
match counts.get(color) {
Some(n) => println!("{color}: {n}"),
None => println!("{color}: 0"),
}
}
}

Salida:

rojo: 3
verde: 1
azul: 2
rosa: 0
▶ Pruébalo tú mismo

or_insert(0) devuelve una referencia mutable al valor guardado en el mapa, no una copia. El * de *count += 1 significa “cambia el número al que apunta”, así que el propio mapa se actualiza. Este patrón de “entry, o inserta 0, y luego suma 1” es la forma habitual de contar cosas en Rust.

  • HashMap<K, V> guarda pares clave-valor; tráelo al ámbito con use std::collections::HashMap;.
  • .insert(clave, valor) añade o sobrescribe; .get(clave) busca y devuelve un Option.
  • .entry(clave).or_insert(valor) inserta solo si la clave todavía no está.
  • El orden al recorrerlo no está garantizado: no dependas de él.

Comprueba lo aprendido

1. A diferencia de Vec o String, ¿qué necesitas para traer HashMap al ámbito?

2. ¿Qué hace .entry(key).or_insert(value)?

3. ¿Puedes confiar en el orden en que se imprimen las entradas al recorrer un HashMap?

Puntuación: 0 / 3