Saya cukup bingung dengan kedua fungsi ini fold()
dan reduce()
di Kotlin, adakah yang bisa memberi saya contoh konkret yang membedakan keduanya?
Saya cukup bingung dengan kedua fungsi ini fold()
dan reduce()
di Kotlin, adakah yang bisa memberi saya contoh konkret yang membedakan keduanya?
Jawaban:
fold
mengambil nilai awal, dan permintaan pertama dari lambda yang Anda lewati akan menerima nilai awal dan elemen pertama dari koleksi sebagai parameter.
Misalnya, ambil kode berikut yang menghitung jumlah daftar bilangan bulat:
listOf(1, 2, 3).fold(0) { sum, element -> sum + element }
Panggilan pertama ke lambda akan dengan parameter 0
dan 1
.
Memiliki kemampuan untuk memberikan nilai awal berguna jika Anda harus memberikan semacam nilai atau parameter default untuk operasi Anda. Misalnya, jika Anda mencari nilai maksimum di dalam daftar, tetapi karena alasan tertentu ingin mengembalikan setidaknya 10, Anda dapat melakukan hal berikut:
listOf(1, 6, 4).fold(10) { max, element ->
if (element > max) element else max
}
reduce
tidak mengambil nilai awal, melainkan mulai dengan elemen pertama koleksi sebagai akumulator (disebut sum
dalam contoh berikut).
Sebagai contoh, mari kita lakukan jumlah bilangan bulat lagi:
listOf(1, 2, 3).reduce { sum, element -> sum + element }
Panggilan pertama ke lambda di sini akan dengan parameter 1
dan 2
.
Anda dapat menggunakannya reduce
saat operasi Anda tidak bergantung pada nilai apa pun selain dari yang ada di koleksi yang Anda lamar.
emptyList<Int>().reduce { acc, s -> acc + s }
akan menghasilkan pengecualian, tetapi emptyList<Int>().fold(0) { acc, s -> acc + s }
tidak masalah.
listOf<Int>(1, 2).reduce { acc: Number, i: Int -> acc.toLong() + i }
(daftar-jenisnya Int sedangkan tipe akumulator dinyatakan sebagai Angka dan sebenarnya Panjang)
Perbedaan fungsional utama yang saya sebut (yang disebutkan dalam komentar pada jawaban lain, tetapi mungkin sulit dimengerti) adalah bahwa reduce
akan mengeluarkan pengecualian jika dilakukan pada koleksi kosong.
listOf<Int>().reduce { x, y -> x + y }
// java.lang.UnsupportedOperationException: Empty collection can't be reduced.
Ini karena .reduce
tidak tahu nilai apa yang dikembalikan jika "tidak ada data".
Bandingkan dengan ini .fold
, yang mengharuskan Anda untuk memberikan "nilai awal", yang akan menjadi nilai default jika koleksi kosong:
val result = listOf<Int>().fold(0) { x, y -> x + y }
assertEquals(0, result)
Jadi, bahkan jika Anda tidak ingin mengagregasi koleksi Anda ke satu elemen dari tipe (tidak terkait) yang berbeda (yang hanya .fold
akan membiarkan Anda melakukannya), jika koleksi awal Anda mungkin kosong maka Anda harus memeriksa koleksi Anda ukuran dulu dan kemudian .reduce
, atau gunakan saja.fold
val collection: List<Int> = // collection of unknown size
val result1 = if (collection.isEmpty()) 0
else collection.reduce { x, y -> x + y }
val result2 = collection.fold(0) { x, y -> x + y }
assertEquals(result1, result2)