Nói chung, tất cả 6 hàm gấp đều áp dụng toán tử nhị phân cho mỗi phần tử của tập hợp. Kết quả của mỗi bước được chuyển sang bước tiếp theo (làm đầu vào cho một trong hai đối số của toán tử nhị phân). Bằng cách này chúng ta có thể tích lũy một kết quả.
reduceLeft
và reduceRight
tích lũy một kết quả duy nhất.
foldLeft
và foldRight
tích lũy một kết quả duy nhất bằng cách sử dụng giá trị bắt đầu.
scanLeft
và scanRight
tích lũy một tập hợp các kết quả tích lũy trung gian bằng cách sử dụng giá trị bắt đầu.
Tích trữ
Từ TRÁI và chuyển tiếp ...
Với bộ sưu tập các phần tử abc
và toán tử nhị phân, add
chúng ta có thể khám phá các hàm gấp khác nhau làm gì khi chuyển tiếp từ phần tử LEFT của bộ sưu tập (từ A đến C):
val abc = List("A", "B", "C")
def add(res: String, x: String) = {
println(s"op: $res + $x = ${res + x}")
res + x
}
abc.reduceLeft(add)
// op: A + B = AB
// op: AB + C = ABC // accumulates value AB in *first* operator arg `res`
// res: String = ABC
abc.foldLeft("z")(add) // with start value "z"
// op: z + A = zA // initial extra operation
// op: zA + B = zAB
// op: zAB + C = zABC
// res: String = zABC
abc.scanLeft("z")(add)
// op: z + A = zA // same operations as foldLeft above...
// op: zA + B = zAB
// op: zAB + C = zABC
// res: List[String] = List(z, zA, zAB, zABC) // maps intermediate results
Từ QUYỀN và ngược ...
Nếu chúng ta bắt đầu với phần tử ĐÚNG và quay ngược (từ C sang A), chúng ta sẽ nhận thấy rằng bây giờ đối số thứ hai cho toán tử nhị phân của chúng ta tích lũy kết quả (toán tử giống nhau, chúng ta chỉ cần chuyển tên đối số để làm rõ vai trò của chúng ):
def add(x: String, res: String) = {
println(s"op: $x + $res = ${x + res}")
x + res
}
abc.reduceRight(add)
// op: B + C = BC
// op: A + BC = ABC // accumulates value BC in *second* operator arg `res`
// res: String = ABC
abc.foldRight("z")(add)
// op: C + z = Cz
// op: B + Cz = BCz
// op: A + BCz = ABCz
// res: String = ABCz
abc.scanRight("z")(add)
// op: C + z = Cz
// op: B + Cz = BCz
// op: A + BCz = ABCz
// res: List[String] = List(ABCz, BCz, Cz, z)
.
Khử tích lũy
Từ TRÁI và chuyển tiếp ...
Nếu thay vào đó, chúng tôi sẽ tích lũy một số kết quả bằng phép trừ bắt đầu từ phần tử TRÁI của bộ sưu tập, chúng tôi sẽ tích lũy kết quả thông qua đối số đầu tiên res
của toán tử nhị phân của chúng tôi minus
:
val xs = List(1, 2, 3, 4)
def minus(res: Int, x: Int) = {
println(s"op: $res - $x = ${res - x}")
res - x
}
xs.reduceLeft(minus)
// op: 1 - 2 = -1
// op: -1 - 3 = -4 // de-cumulates value -1 in *first* operator arg `res`
// op: -4 - 4 = -8
// res: Int = -8
xs.foldLeft(0)(minus)
// op: 0 - 1 = -1
// op: -1 - 2 = -3
// op: -3 - 3 = -6
// op: -6 - 4 = -10
// res: Int = -10
xs.scanLeft(0)(minus)
// op: 0 - 1 = -1
// op: -1 - 2 = -3
// op: -3 - 3 = -6
// op: -6 - 4 = -10
// res: List[Int] = List(0, -1, -3, -6, -10)
Từ QUYỀN và ngược ...
Nhưng xem ra các biến thể xRight bây giờ! Hãy nhớ rằng giá trị tích lũy (khử) trong các biến thể xRight được truyền cho tham số thứ haires
của toán tử nhị phân của chúng tôi minus
:
def minus(x: Int, res: Int) = {
println(s"op: $x - $res = ${x - res}")
x - res
}
xs.reduceRight(minus)
// op: 3 - 4 = -1
// op: 2 - -1 = 3 // de-cumulates value -1 in *second* operator arg `res`
// op: 1 - 3 = -2
// res: Int = -2
xs.foldRight(0)(minus)
// op: 4 - 0 = 4
// op: 3 - 4 = -1
// op: 2 - -1 = 3
// op: 1 - 3 = -2
// res: Int = -2
xs.scanRight(0)(minus)
// op: 4 - 0 = 4
// op: 3 - 4 = -1
// op: 2 - -1 = 3
// op: 1 - 3 = -2
// res: List[Int] = List(-2, 3, -1, 4, 0)
Danh sách cuối cùng (-2, 3, -1, 4, 0) có thể không phải là những gì bạn mong đợi bằng trực giác!
Như bạn thấy, bạn có thể kiểm tra xem FoldX của bạn đang làm gì bằng cách chạy scanX thay vào đó và gỡ lỗi kết quả tích lũy ở mỗi bước.
Dòng dưới cùng