Lewati ke konten

HashMap di Rust

HashMap menyimpan data sebagai pasangan key-value (kunci-nilai). Kamu mencari data berdasarkan key, bukan berdasarkan posisi seperti pada array atau vektor. Kalau kamu pernah memakai dictionary di Python atau object sebagai map di JavaScript, idenya sama persis.

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

Baris use std::collections::HashMap; di bagian atas membawa tipe ini ke dalam cakupan (scope). Berbeda dengan Vec dan String, HashMap tidak tersedia secara otomatis, jadi baris ini wajib ada.

▶ Coba sendiri
use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
match ages.get("Alice") {
Some(age) => println!("Umur Alice {age} tahun"),
None => println!("Tidak ditemukan"),
}
}
▶ Coba sendiri

.get() mengembalikan Option, bukan nilainya langsung, karena bisa saja key-nya tidak ada. Kita akan membahas Option dengan lengkap di halamannya sendiri. Untuk sekarang, match dengan Some/None adalah cara standar untuk menanganinya.

Melakukan insert lagi dengan key yang sama akan menimpa nilai yang lama:

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.insert("Alice", 31); // menimpa 30
println!("{:?}", ages.get("Alice"));
}
▶ Coba sendiri

Kalau kamu hanya ingin memasukkan nilai ketika key-nya belum ada, pakai .entry():

use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.entry("Alice").or_insert(99); // Alice sudah ada, jadi ini tidak melakukan apa-apa
ages.entry("Bob").or_insert(25); // Bob belum ada, jadi ini memasukkannya
println!("{:?}", ages);
}
▶ Coba sendiri
use std::collections::HashMap;
fn main() {
let mut ages = HashMap::new();
ages.insert("Alice", 30);
ages.insert("Bob", 25);
for (name, age) in &ages {
println!("Umur {name} {age} tahun");
}
}
▶ Coba sendiri

Pakai HashMap setiap kali kamu ingin mencari sesuatu berdasarkan nama atau ID, bukan berdasarkan posisi: menghitung frekuensi kata, memetakan username ke data pengguna, atau menyimpan cache hasil berdasarkan key. Kalau urutan penting atau kamu hanya mengolah daftar biasa, Vec lebih cocok.

Simpan tiga nama beserta nomor teleponnya di sebuah HashMap. Lalu cari "Ben" (yang ada di dalamnya) dan "Dana" (yang tidak ada), dan cetak satu baris yang ramah untuk masing-masing. Petunjuk: lakukan perulangan pada ["Ben", "Dana"] dan pakai match pada .get(name).

Lihat solusi
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}: tidak ada di buku telepon"),
}
}
}

Output:

Ben: 555-9876
Dana: tidak ada di buku telepon
▶ Coba sendiri

Melakukan perulangan pada nama-nama yang kita cari, bukan pada map-nya, juga memberi kita urutan yang tetap. Trik ini berguna setiap kali kamu butuh output yang bisa ditebak dari sebuah HashMap.

Kamu punya suara ["merah", "biru", "merah", "hijau", "biru", "merah"]. Hitung berapa suara yang didapat setiap warna, lalu cetak totalnya untuk "merah", "hijau", "biru", dan "pink" (yang tidak dapat suara sama sekali). Petunjuk: counts.entry(color).or_insert(0) memberimu jumlah saat ini untuk warna itu, dimulai dari 0. Tambahkan satu dengan *count += 1.

Lihat solusi
use std::collections::HashMap;
fn main() {
let votes = ["merah", "biru", "merah", "hijau", "biru", "merah"];
let mut counts = HashMap::new();
for color in votes {
let count = counts.entry(color).or_insert(0);
*count += 1;
}
for color in ["merah", "hijau", "biru", "pink"] {
match counts.get(color) {
Some(n) => println!("{color}: {n}"),
None => println!("{color}: 0"),
}
}
}

Output:

merah: 3
hijau: 1
biru: 2
pink: 0
▶ Coba sendiri

or_insert(0) mengembalikan referensi mutable ke nilai yang tersimpan di map, bukan salinannya. Tanda * pada *count += 1 artinya “ubah angka yang ditunjuk oleh ini”, sehingga map-nya sendiri ikut diperbarui. Pola “entry, atau insert 0, lalu tambah 1” ini adalah cara standar untuk menghitung sesuatu di Rust.

  • HashMap<K, V> menyimpan pasangan key-value; bawa ke dalam cakupan dengan use std::collections::HashMap;.
  • .insert(key, value) menambah atau menimpa; .get(key) mencari dan mengembalikan Option.
  • .entry(key).or_insert(value) hanya memasukkan nilai kalau key-nya belum ada.
  • Urutan saat perulangan tidak dijamin, jadi jangan bergantung padanya.

Kuis singkat

1. Apa yang kamu perlukan untuk membawa HashMap ke dalam cakupan, tidak seperti Vec atau String?

2. Apa yang dilakukan .entry(key).or_insert(value)?

3. Bisakah kamu mengandalkan urutan entri yang tercetak saat perulangan pada HashMap?

Skor: 0 / 3