dartlistfoldreduceMenengah4 mnt baca

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

dart
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:

dart
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

dart
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

dart
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

dart
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

dart
// SALAH: akumulator String tapi operasi angka
void main() {
  var angka = [1, 2, 3];
  // var x = angka.fold(0, (s, n) => '$s$n'); // tipe berantakan
}
dart
// 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: fold dan kawan-kawan bekerja pada Iterable, jadi bisa dirantai setelah where/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.

text
void main() {
  var belanja = [15000, 25000, 10000, 30000];
  // TODO: total (fold), termahal (reduce), semuaDiAtas5000 (every)
}