Agregasi

sum, count, maxOrNull, fold, dan reduce pada collection.

Daftar isi

Agregasi merangkum sebuah collection menjadi satu nilai, misalnya total, nilai terbesar, atau hasil akumulasi bertahap. Topik ini membahas sum dan count untuk penghitungan cepat, maxOrNull dan minOrNull untuk nilai ujung, fold yang menyertakan nilai awal, serta reduce yang memakai elemen pertama sebagai titik mula. Kasus collection kosong dibahas tersendiri karena di sanalah perbedaan perilaku antarfungsi terlihat. Seluruh contoh dijalankan dengan compiler Kotlin sehingga keluarannya berasal dari eksekusi nyata.

sum dan count#

Fungsi sum menjumlahkan seluruh elemen bilangan, sedangkan count menghitung jumlah elemen. Bentuk dengan lambda, yaitu count { kondisi }, hanya menghitung elemen yang lulus kondisi tersebut. Keduanya menghasilkan satu bilangan tanpa perulangan yang ditulis manual. Program berikut menerapkannya pada lima nilai ujian.

kotlin hitung.kt
fun main() {
    val nilai = listOf(80, 65, 90, 55, 75)
    println(nilai.sum())
    println(nilai.count())
    println(nilai.count { it >= 75 })
}
bash
# compiler Kotlin dan pustaka standar yang dipakai jalur ini
export PATH=/home/kal/my-project/tools/kotlinc/bin:/home/kal/my-project/tools/jdk-merged/bin:$PATH
export STDLIB=/home/kal/my-project/tools/kotlinc/lib/kotlin-stdlib.jar

# kompilasi hitung.kt menjadi hitung.jar, lalu jalankan programnya
kotlinc hitung.kt -d hitung.jar && java -cp "hitung.jar:$STDLIB" HitungKt
text Keluaran
365
5
3

Keluaran 365 adalah jumlah kelima nilai, sedangkan 5 adalah banyaknya elemen pada daftar. Pemanggilan count { it >= 75 } menghasilkan 3 karena hanya 80, 90, dan 75 yang lulus syarat. Bentuk count dengan lambda setara dengan filter { ... }.size, tetapi tidak membentuk daftar perantara, sehingga lebih ringkas untuk sekadar penghitungan.

maxOrNull dan minOrNull#

Fungsi maxOrNull dan minOrNull mencari nilai terbesar dan terkecil pada collection bilangan. Akhiran OrOrNull menandai kontraknya, yaitu menghasilkan null alih-alih melempar error ketika collection tidak memuat elemen apa pun. Program berikut memanggil keduanya pada data lengkap dan pada daftar kosong.

kotlin ujung.kt
fun main() {
    val nilai = listOf(80, 65, 90, 55, 75)
    println(nilai.maxOrNull())
    println(nilai.minOrNull())

    val kosong = listOf<Int>()
    println(kosong.maxOrNull())
}
bash
# kompilasi ujung.kt menjadi ujung.jar, lalu jalankan programnya
kotlinc ujung.kt -d ujung.jar && java -cp "ujung.jar:$STDLIB" UjungKt
text Keluaran
90
55
null

Keluaran 90 dan 55 adalah nilai terbesar dan terkecil dari lima data tersebut. Pemanggilan yang sama pada daftar kosong menghasilkan null dan bukan error, karena tidak ada nilai yang dapat dilaporkan. Hasil bertipe nullable ini menuntut penanganan null sebelum nilainya dipakai, misalnya lewat operator elvis, sehingga kasus daftar kosong tidak terlupakan.

fold dengan nilai awal#

Fungsi fold menumpuk seluruh elemen menjadi satu nilai dengan menyertakan nilai awal. Lambda fold menerima dua parameter, yaitu akumulasi dan elemen yang sedang diproses, lalu hasilnya menjadi akumulasi untuk putaran berikutnya. Nilai awal sekaligus menjadi hasil akhir apabila collection kosong, sehingga fold aman dipanggil tanpa memeriksa isi collection terlebih dahulu.

kotlin lipat.kt
fun main() {
    val nilai = listOf(80, 65, 90, 55, 75)
    val total = nilai.fold(0) { akumulasi, n -> akumulasi + n }
    println(total)
    val totalSkor = nilai.fold(100) { akumulasi, n -> akumulasi + n }
    println(totalSkor)
    val rangkuman = nilai.fold("") { teks, n -> "$teks$n " }
    println(rangkuman)
}
bash
# kompilasi lipat.kt menjadi lipat.jar, lalu jalankan programnya
kotlinc lipat.kt -d lipat.jar && java -cp "lipat.jar:$STDLIB" LipatKt
text Keluaran
365
465
80 65 90 55 75 

Pemanggilan fold(0) menghasilkan 365, yaitu jumlah seluruh nilai, sedangkan fold(100) menghasilkan 465 karena 100 ikut dihitung sebagai titik mula. Contoh ketiga memperlihatkan fleksibilitas fold, yaitu menumpuk string dengan nilai awal berupa string kosong sehingga keluarannya berupa deretan angka berdampingan. Tipe nilai awal menentukan tipe akumulasi, sehingga fungsi yang sama dapat menghasilkan bilangan maupun teks sesuai titik mulanya.

reduce dan collection kosong#

Fungsi reduce bekerja seperti fold tanpa nilai awal, yaitu elemen pertama dipakai sebagai akumulasi pertama dan lambda memproses sisanya. Bentuk ini ringkas untuk data yang dijamin memiliki elemen, misalnya mencari nilai terbesar dengan perbandingan berulang.

kotlin reduksi.kt
fun main() {
    val nilai = listOf(80, 65, 90, 55, 75)
    val tertinggi = nilai.reduce { tercatat, n -> if (n > tercatat) n else tercatat }
    println(tertinggi)
}
bash
# kompilasi reduksi.kt menjadi reduksi.jar, lalu jalankan programnya
kotlinc reduksi.kt -d reduksi.jar && java -cp "reduksi.jar:$STDLIB" ReduksiKt
text Keluaran
90

Lambda if (n > tercatat) n else tercatat membandingkan elemen berikutnya dengan nilai yang tercatat dan mempertahankan yang lebih besar, sehingga hasil akhirnya adalah nilai terbesar. Perilaku ini berbeda dari maxOrNull hanya pada sumber titik mulanya, yaitu elemen pertama daripada nilai awal eksplisit.

Perbedaan dengan fold muncul pada collection kosong. Karena tidak ada elemen pertama yang dapat menjadi akumulasi awal, reduce memunculkan error saat program berjalan sebagaimana berikut.

kotlin kosong.kt
fun main() {
    val kosong = listOf<Int>()
    println(kosong.reduce { tercatat, n -> tercatat + n })
}
bash
# kompilasi kosong.kt lalu jalankan programnya untuk melihat error saat berjalan
kotlinc kosong.kt -d kosong.jar && java -cp "kosong.jar:$STDLIB" KosongKt
text Keluaran
Exception in thread "main" java.lang.UnsupportedOperationException: Empty collection can't be reduced.
	at KosongKt.main(kosong.kt:7)
	at KosongKt.main(kosong.kt)

Pesan UnsupportedOperationException: Empty collection can't be reduced menyatakan bahwa collection kosong tidak dapat direduksi. Baris yang ditunjuk pelacakan tumpukan tidak identik dengan baris pemanggilannya karena badan fungsi inline reduce disisipkan ke dalam kode program oleh compiler. Perbaikannya memilih fungsi yang cocok dengan bentuk datanya, yaitu fold dengan nilai awal bila collection bisa kosong, atau reduceOrNull yang menghasilkan null alih-alih error.

Ringkasan#

  • sum menjumlahkan seluruh elemen bilangan, sedangkan count menghitung elemen, baik seluruhnya maupun yang lulus kondisi lambda.
  • maxOrNull dan minOrNull menghasilkan nilai terbesar dan terkecil, atau null bila collection kosong.
  • fold menumpuk elemen menjadi satu nilai dengan nilai awal eksplisit, sehingga collection kosong tetap menghasilkan nilai.
  • reduce memakai elemen pertama sebagai akumulasi awal dan melempar UnsupportedOperationException pada collection kosong.

Referensi#