dartmapcollectionMenengah4 mnt baca

Map

Pasangan key-value: membuat, mengakses, dan mengolah Map.

Data berpasangan: kunci dan nilai

List menyimpan nilai berurutan, Set menyimpan nilai unik. Tapi bagaimana menyimpan "nama → Budi", "umur → 17"? Data dunia nyata sering berbentuk pasangan kunci-nilai: kamus kata-arti, username-password, kode pos-kota. Map adalah koleksi untuk itu.

Analogi: map itu seperti kamus. Kamu tidak mencari arti kata dengan memindai semua halaman (seperti list), kamu langsung buka berdasarkan kata kunci (key) dan dapat artinya (value).

Kenapa Map ada?

Karena pencarian berdasarkan kunci adalah kebutuhan universal: data pengguna berdasarkan ID, konfigurasi berdasarkan nama, cache berdasarkan URL. Map memberi akses langsung O(1) ke nilai lewat kuncinya, tanpa loop.

Membuat dan memakai Map

dart
void main() {
  // Map<String, String>: kunci String, nilai String
  Map<String, String> kamus = {
    'apel': 'apple',
    'mangga': 'mango',
  };

  print(kamus['apel']); // apple, akses lewat kunci
  print(kamus['durian']); // null, kunci tidak ada

  kamus['pisang'] = 'banana'; // tambah pasangan baru
  kamus['apel'] = 'APPLE';    // timpa nilai kunci yang ada
  print(kamus);

  print(kamus.keys);   // (apel, mangga, pisang)
  print(kamus.values); // (APPLE, mango, banana)
  print(kamus.length); // 3
}

Poin penting: mengakses kunci yang tidak ada menghasilkan null, bukan error. Itu sebabnya tipe hasilnya nullable dan sering dipadukan dengan ??.

Contoh kedua, map dengan tipe nilai campuran untuk data pengguna:

dart
void main() {
  Map<String, dynamic> user = {
    'nama': 'Budi',
    'umur': 17,
    'aktif': true,
    'hobi': ['membaca', 'ngoding'],
  };

  print('Nama: ${user['nama']}');
  print('Hobi pertama: ${user['hobi'][0]}');

  // Iterasi semua pasangan
  user.forEach((kunci, nilai) {
    print('$kunci => $nilai');
  });

  user.remove('aktif'); // hapus pasangan
  print(user.containsKey('aktif')); // false
}

Map<String, dynamic> sangat umum untuk data JSON dari API. Nilai dynamic artinya "tipe apa pun", fleksibel tapi butuh kehati-hatian.

Kunci harus unik

dart
void main() {
  var m = {'a': 1, 'b': 2};
  m['a'] = 99; // kunci 'a' sudah ada: nilainya DITIMPA, bukan dobel
  print(m); // {a: 99, b: 2}
  print(m.length); // 2, tidak bertambah
}

Seperti Set, kunci map bersifat unik. Menulis ke kunci yang sama menimpa nilai lama. Ini fitur, bukan bug: cache[url] = data selalu menyimpan versi terbaru.

Kesalahan umum

1. Lupa hasil akses bisa null

dart
// SALAH: crash jika kunci tidak ada
void main() {
  var kamus = {'apel': 'apple'};
  // print(kamus['durian']!.length); // ERROR: null!
}
dart
// BENAR: sediakan default dengan ??
void main() {
  var kamus = {'apel': 'apple'};
  print(kamus['durian'] ?? 'tidak ada'); // tidak ada
  print(kamus['apel']?.length); // 5, aman dengan ?.
}

2. Salah tipe kunci

dart
// SALAH
void main() {
  var m = {1: 'satu', 2: 'dua'}; // Map<int, String>
  // print(m['1']); // null! '1' String != 1 int
  print(m[1]); // satu
}

Kunci 1 (int) dan '1' (String) adalah dua kunci berbeda. Konsistenlah dengan tipe kunci.

3. Mengubah map saat diiterasi

dart
// SALAH: error ConcurrentModificationError
void main() {
  var m = {'a': 1, 'b': 2};
  // for (var k in m.keys) {
  //   m.remove(k);
  // }
}
dart
// BENAR: iterasi salinan kunci dulu
void main() {
  var m = {'a': 1, 'b': 2};
  for (var k in m.keys.toList()) {
    m.remove(k);
  }
  print(m); // {}
}

Kesimpulan

Map = pasangan kunci-nilai unik, akses map[kunci] menghasilkan null jika tak ada (pakai ??), kunci bersifat unik dan menimpa. Map<String, dynamic> adalah jembatan utama ke data JSON.

Catatan teknis: Di balik layar, Map memakai hash table seperti Set, sehingga akses kunci O(1). Iterasi map mengikuti urutan penyisipan (insertion order) di implementasi default LinkedHashMap.

Tantangan

Kasir sederhana

Diberi Map harga barang dan list belanjaan, hitung total bayar. Pakai ?? 0 agar barang yang tidak ada di harga tidak error.

text
void main() {
  var harga = {'nasi': 5000, 'ayam': 8000, 'es teh': 3000};
  var belanja = ['nasi', 'ayam', 'ayam', 'kerupuk'];
  // TODO: hitung total
}