Mẫu Iterator
Thuộc phần Lập trình hướng đối tượng trong hành trình R của Coddy. Bài học 49 trên 57.
Một bộ lặp lần lượt cung cấp từng phần tử của một tập hợp, nên đoạn code sử dụng các phần tử đó không cần biết tập hợp được lưu trữ như thế nào. Một bao đóng giữ vị trí; has_next() và next_value() là toàn bộ giao diện:
make_iterator <- function(x) {
i <- 0
list(
has_next = function() i < length(x),
next_value = function() {
i <<- i + 1
x[[i]]
}
)
}
it <- make_iterator(c("a", "b", "c"))
while (it$has_next()) cat(it$next_value(), "")Đầu ra:
a b c Bộ sinh (generator) là một trình lặp tính từng giá trị khi được yêu cầu, nên dãy không cần tồn tại trong bộ nhớ. Dãy thậm chí có thể kéo dài vô tận:
make_fib <- function() {
a <- 0
b <- 1
list(has_next = function() TRUE,
next_value = function() {
value <- a
nxt <- a + b
a <<- b
b <<- nxt
value
})
}
fib <- make_fib()
for (i in 1:10) cat(fib$next_value(), "")Đầu ra:
0 1 1 2 3 5 8 13 21 34 Bộ lặp ẩn đi cách sắp xếp. Các kết quả được lưu trong những trang, một số trang trống, sẽ được trả ra thành một dãy phẳng duy nhất:
make_paged <- function(pages) {
p <- 1
i <- 0
skip_empty <- function() while (p <= length(pages) && i >= length(pages[[p]])) { p <<- p + 1; i <<- 0 }
list(
has_next = function() { skip_empty(); p <= length(pages) },
next_value = function() { skip_empty(); i <<- i + 1; pages[[p]][i] }
)
}
it <- make_paged(list(c("a", "b"), character(0), c("c")))
while (it$has_next()) cat(it$next_value(), "")Đầu ra:
a b c Các hàm trợ giúp được viết dựa trên giao diện sẽ hoạt động với mọi trình lặp. take(it, n) lấy tối đa n giá trị từ một vector, một hàm sinh hoặc bất kỳ thứ gì khác có has_next() và next_value():
make_iterator <- function(x) {
i <- 0
list(has_next = function() i < length(x), next_value = function() { i <<- i + 1; x[[i]] })
}
take <- function(it, n) {
out <- c()
while (length(out) < n && it$has_next()) out <- c(out, it$next_value())
out
}
it <- make_iterator(1:5)
print(take(it, 2))
print(take(it, 10))Đầu ra:
[1] 1 2
[1] 3 4 5Thử thách
DễHoàn thành Iterator.R:
make_iterator(x): một bộ lặp qua các phần tử của một vectơ, cóhas_next()vànext_value();make_range(from, to, by): một bộ tạo các giá trịfrom,from + by, ... cho đến và bao gồmto, được tính lần lượt từng giá trị;take(it, n): lấy tối đangiá trị tiếp theo từ bất kỳ bộ lặp nào.
Code được cung cấp đọc các dòng range 1 10 3 take 2 5 (from, to, by, sau đó là kích thước của mỗi lần take) hoặc list a,b,c take 2 2, rồi in ra giá trị mà mỗi take() trả về.
Code của bạn nằm trong Iterator.R. main.R chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
source("Iterator.R")
# Đoạn code đầu vào/đầu ra đã cho: giữ nguyên
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, " ")[[1]]
it <- if (p[1] == "range") make_range(as.numeric(p[2]), as.numeric(p[3]), as.numeric(p[4])) else make_iterator(strsplit(p[2], ",")[[1]])
k <- if (p[1] == "range") 5 else 3
for (n in as.numeric(p[-(1:k)])) {
got <- take(it, n)
cat("take ", n, ": ", if (length(got) == 0) "(nothing)" else paste(got, collapse = " "), "\n", sep = "")
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Kiến thức cơ bản về S3
Làm việc với tệpDanh sách với một lớpHàm khởi tạoPhương thức in ra và định dạngTrình xác thực và hàm hỗ trợÔn tập: nhiệt độ4Tính đóng gói trong R
Closure dưới dạng đối tượngMôi trường dưới dạng đối tượngHàm truy cậpBảo vệ trạng tháiÔn tập: đồng hồ tính phí đỗ xe2S3, hàm generic và phương thức
Hàm generic và UseMethodPhương thức mặc địnhPhương thức cho hàm generic cơ sởCơ bản về NextMethodÔn tập: diện tích hình5Các lớp S4
Định nghĩa lớp S4Slot và quyền truy cậpKiểm tra tính hợp lệPhương thức showÔn tập: Danh mục sản phẩmTự luyện tập: Trình biên dịch R online