Tôi khá bối rối với cả hai chức năng này fold()
và reduce()
trong Kotlin, bất cứ ai cũng có thể cho tôi một ví dụ cụ thể để phân biệt cả hai chức năng này không?
Tôi khá bối rối với cả hai chức năng này fold()
và reduce()
trong Kotlin, bất cứ ai cũng có thể cho tôi một ví dụ cụ thể để phân biệt cả hai chức năng này không?
Câu trả lời:
fold
nhận một giá trị ban đầu và lệnh gọi đầu tiên của lambda mà bạn truyền tới nó sẽ nhận giá trị ban đầu đó và phần tử đầu tiên của bộ sưu tập làm tham số.
Ví dụ: lấy mã sau để tính tổng của danh sách các số nguyên:
listOf(1, 2, 3).fold(0) { sum, element -> sum + element }
Cuộc gọi đầu tiên đến lambda sẽ có các tham số 0
và 1
.
Có khả năng vượt qua trong một giá trị ban đầu là hữu ích nếu bạn phải cung cấp một số loại giá trị hoặc tham số mặc định cho hoạt động của mình. Ví dụ: nếu bạn đang tìm kiếm giá trị tối đa trong danh sách, nhưng vì lý do nào đó muốn trả về ít nhất 10, bạn có thể làm như sau:
listOf(1, 6, 4).fold(10) { max, element ->
if (element > max) element else max
}
reduce
không lấy một giá trị ban đầu, mà thay vào đó bắt đầu bằng phần tử đầu tiên của bộ sưu tập dưới dạng bộ tích lũy (được gọi sum
trong ví dụ sau).
Ví dụ: hãy thực hiện lại tổng số nguyên:
listOf(1, 2, 3).reduce { sum, element -> sum + element }
Cuộc gọi đầu tiên đến lambda ở đây sẽ có các tham số 1
và 2
.
Bạn có thể sử dụng reduce
khi hoạt động của bạn không phụ thuộc vào bất kỳ giá trị nào ngoài các giá trị trong bộ sưu tập bạn đang áp dụng.
emptyList<Int>().reduce { acc, s -> acc + s }
sẽ tạo ra một ngoại lệ, nhưng emptyList<Int>().fold(0) { acc, s -> acc + s }
vẫn ổn.
listOf<Int>(1, 2).reduce { acc: Number, i: Int -> acc.toLong() + i }
(kiểu danh sách là Int trong khi kiểu trình tích lũy được khai báo là Số và thực sự là Dài)
Sự khác biệt lớn về chức năng mà tôi sẽ gọi ra (được đề cập trong các bình luận về câu trả lời khác, nhưng có thể khó hiểu) là điều đó reduce
sẽ tạo ra một ngoại lệ nếu được thực hiện trên một bộ sưu tập trống.
listOf<Int>().reduce { x, y -> x + y }
// java.lang.UnsupportedOperationException: Empty collection can't be reduced.
Điều này là do .reduce
không biết giá trị nào sẽ trả về trong trường hợp "không có dữ liệu".
Tương phản điều này với .fold
, yêu cầu bạn cung cấp "giá trị bắt đầu", đây sẽ là giá trị mặc định trong trường hợp bộ sưu tập trống:
val result = listOf<Int>().fold(0) { x, y -> x + y }
assertEquals(0, result)
Vì vậy, ngay cả khi bạn không muốn tổng hợp bộ sưu tập của mình thành một yếu tố duy nhất thuộc loại khác (không liên quan) (chỉ .fold
cho phép bạn làm), nếu bộ sưu tập bắt đầu của bạn có thể trống thì bạn phải kiểm tra bộ sưu tập của mình kích thước đầu tiên và sau đó .reduce
, hoặc chỉ sử dụng.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)