Agregasi List: fold, reduce, every
Meringkas list jadi satu nilai: fold, reduce, every, any, dan statistik.
Dari banyak nilai ke satu nilai
map/where mengubah list menjadi list. Tapi sering kamu butuh sebaliknya: meringkas list menjadi SATU nilai, seperti total belanja, nilai tertinggi, atau "apakah semua lulus?". Inilah agregasi.
Analogi: agregasi itu seperti kasir yang mengubah sekeranjang barang menjadi satu angka total. Barang banyak, hasil satu.
Kenapa agregasi ada?
Karena pola "loop + akumulator" muncul di mana-mana dan rawan salah (lupa inisialisasi, salah operator). Method agregasi membungkus pola itu dengan nama yang jelas.
fold vs reduce
void main() {
var angka = [1, 2, 3, 4, 5];
// fold: mulai dari nilai awal 0
var total = angka.fold(0, (sebelumnya, n) => sebelumnya + n);
print(total); // 15
// reduce: mulai dari elemen pertama (tanpa nilai awal)
var total2 = angka.reduce((sebelumnya, n) => sebelumnya + n);
print(total2); // 15
// fold bisa mengubah tipe: list -> String
var kalimat = angka.fold('', (s, n) => '$s$n-');
print(kalimat); // 1-2-3-4-5-
}Perbedaan kunci:
fold(nilaiAwal, fungsi): butuh nilai awal, boleh menghasilkan tipe berbeda.reduce(fungsi): tanpa nilai awal, tipe hasil = tipe elemen. ERROR jika list kosong!
Contoh kedua, agregasi praktis:
void main() {
var belanja = [15000, 25000, 10000, 30000];
var total = belanja.fold(0, (a, b) => a + b);
var termahal = belanja.reduce((a, b) => a > b ? a : b);
var rata = total / belanja.length;
print('Total: $total');
print('Termahal: $termahal');
print('Rata-rata: $rata');
}every, any: agregasi boolean
void main() {
var nilai = [80, 90, 75, 88];
print(nilai.every((n) => n >= 70)); // true: SEMUA lulus?
print(nilai.any((n) => n == 100)); // false: ADA yang sempurna?
print(nilai.any((n) => n < 70)); // false: ADA yang remedial?
// Kombinasi dengan where untuk statistik
var lulus = nilai.where((n) => n >= 70).length;
print('$lulus dari ${nilai.length} lulus');
}every = "apakah semua memenuhi?", any = "apakah ada yang memenuhi?". Keduanya berhenti lebih awal (short-circuit) begitu jawabannya pasti.
first, last, single
void main() {
var antrean = ['Budi', 'Ani', 'Cici'];
print(antrean.first); // Budi
print(antrean.last); // Cici
// Dengan syarat
print(antrean.firstWhere((n) => n.startsWith('A'))); // Ani
print(antrean.lastWhere((n) => n.length > 3)); // Cici
var satu = ['tunggal'];
print(satu.single); // 'tunggal', ERROR jika bukan tepat 1 elemen
}Kesalahan umum
1. reduce pada list kosong
void main() {
var kosong = <int>[];
// print(kosong.reduce((a, b) => a + b)); // StateError!
print(kosong.fold(0, (a, b) => a + b)); // 0, aman
}Tidak yakin list berisi? Pakai fold dengan nilai awal yang masuk akal.
2. fold dengan tipe akumulator salah
// SALAH: akumulator String tapi operasi angka
void main() {
var angka = [1, 2, 3];
// var x = angka.fold(0, (s, n) => '$s$n'); // tipe berantakan
}// BENAR: tipe awal menentukan tipe hasil
void main() {
var angka = [1, 2, 3];
String s = angka.fold('', (sebelumnya, n) => '$sebelumnya$n,');
print(s); // 1,2,3,
}3. every/any pada list kosong
[].every(...) = true (vacuous truth), [].any(...) = false. Secara matematis benar, tapi bisa mengejutkan. Jika penting, cek isEmpty dulu.
Kesimpulan
Agregasi = list menjadi satu nilai. fold (dengan nilai awal, fleksibel), reduce (tanpa nilai awal, list tak boleh kosong), every/any (cek boolean), first/last/single. Gantikan loop akumulator manual dengan method yang namanya menjelaskan niat.
Catatan teknis:
folddan kawan-kawan bekerja padaIterable, jadi bisa dirantai setelahwhere/map:nilai.where((n) => n > 0).fold(0, (a, b) => a + b). Rantai tetap lazy sampai akhir.
Tantangan
Statistik belanja
Dari belanja = [15000, 25000, 10000, 30000], hitung dengan fold/reduce/every: total, termahal, dan apakah semua di atas 5000. Cetak ketiganya.
void main() {
var belanja = [15000, 25000, 10000, 30000];
// TODO: total (fold), termahal (reduce), semuaDiAtas5000 (every)
}