Transformasi List: map & where
Mengubah dan memfilter list secara deklaratif dengan map, where, expand.
Dari loop manual ke gaya deklaratif
Untuk menggandakan tiap elemen list, cara lama butuh loop + list kosong + add. map dan where menggantikannya dengan satu baris yang mendeklarasikan hasil yang diinginkan, bukan langkahnya.
Analogi: loop manual itu seperti memberi tahu asisten langkah demi langkah ("ambil yang pertama, kali dua, taruh di kotak..."). map/where itu seperti berkata "kalikan semua dengan dua", asisten yang mengurus caranya.
Kenapa gaya deklaratif menang?
Tiga alasan: lebih ringkas (1 baris vs 5), lebih jelas (niat terlihat langsung), dan lebih aman (tidak ada index, tidak ada off-by-one). Di Flutter, 90% pengolahan list memakai gaya ini.
map: ubah tiap elemen
void main() {
var angka = [1, 2, 3, 4];
// Cara lama
var hasil1 = <int>[];
for (var n in angka) {
hasil1.add(n * 2);
}
// Cara map: satu baris
var hasil2 = angka.map((n) => n * 2).toList();
print(hasil1); // [2, 4, 6, 8]
print(hasil2); // [2, 4, 6, 8]
}map menerapkan fungsi ke tiap elemen dan mengumpulkan hasilnya. Jangan lupa .toList(): map mengembalikan Iterable malas.
Contoh kedua, map mengubah tipe:
class Siswa {
String nama;
int nilai;
Siswa(this.nama, this.nilai);
}
void main() {
var siswa = [Siswa('Budi', 85), Siswa('Ani', 92)];
// List<Siswa> -> List<String>
var nama = siswa.map((s) => s.nama).toList();
print(nama); // [Budi, Ani]
// List<Siswa> -> List<String> yang diformat
var laporan = siswa.map((s) => '${s.nama}: ${s.nilai}').toList();
print(laporan); // [Budi: 85, Ani: 92]
}Di Flutter, pola ini dipakai terus: listSiswa.map((s) => Text(s.nama)).toList() mengubah data menjadi widget.
where: saring elemen
void main() {
var nilai = [55, 80, 45, 90, 70];
var lulus = nilai.where((n) => n >= 70).toList();
print(lulus); // [80, 90, 70]
// Rantai: saring lalu ubah
var pesan = nilai
.where((n) => n < 70)
.map((n) => 'Remedial: $n')
.toList();
print(pesan); // [Remedial: 55, Remedial: 45]
}where mempertahankan elemen yang memenuhi syarat. Rantai where→map adalah pola harian: saring dulu, ubah kemudian.
expand: ratakan list bersarang
void main() {
var grup = [
[1, 2],
[3, 4],
[5]
];
var rata = grup.expand((g) => g).toList();
print(rata); // [1, 2, 3, 4, 5]
// Tiap elemen jadi BANYAK elemen
var kata = ['hi', 'yo'];
print(kata.expand((k) => k.split('')).toList()); // [h, i, y, o]
}expand memetakan tiap elemen menjadi iterable, lalu meratakannya. Lawan dari map yang 1-ke-1, expand itu 1-ke-banyak.
Kesalahan umum
1. Lupa toList()
void main() {
var angka = [1, 2, 3];
var hasil = angka.map((n) => n * 2);
print(hasil); // (2, 4, 6) <- Iterable, bukan List!
// hasil.add(10); // ERROR
var listHasil = hasil.toList();
listHasil.add(10);
print(listHasil); // [2, 4, 6, 10]
}2. Mengira map mengubah list asli
void main() {
var angka = [1, 2, 3];
angka.map((n) => n * 2); // hasil dibuang!
print(angka); // [1, 2, 3], tidak berubah
}map/where tidak mengubah asli; mereka menghasilkan koleksi baru. Simpan hasilnya!
3. where dengan efek samping
// BURUK: where untuk aksi, bukan filter
void main() {
var angka = [1, 2, 3];
// angka.where((n) { print(n); return true; }).toList();
}Butuh aksi per elemen? Pakai forEach atau for-in. where hanya untuk memfilter.
Kesimpulan
map = ubah tiap elemen (1-ke-1), where = saring, expand = ratakan (1-ke-banyak). Selalu akhiri dengan .toList() jika butuh List. Gaya deklaratif ini adalah bahasa sehari-hari Dart modern dan Flutter.
Catatan teknis: Rantai map/where bersifat lazy: tidak ada komputasi sampai diiterasi. Untuk list besar, ini hemat memori dibanding membuat list perantara di tiap tahap.
Tantangan
Laporan nilai
Dari list nilai [55, 80, 45, 90, 70], buat list string laporan HANYA untuk yang lulus (>= 70) dengan format 'Nilai 80: LULUS'. Pakai where + map + toList.
void main() {
var nilai = [55, 80, 45, 90, 70];
// TODO: where + map + toList
}