نمط المكرّر
جزء من قسم البرمجة كائنية التوجه في رحلة R على Coddy. الدرس 49 من 57.
يقوم المكرّر بتسليم عناصر مجموعة واحدًا تلو الآخر، لذلك لا يحتاج الكود الذي يستخدمها إلى معرفة كيفية تخزين المجموعة. يحتفظ الإغلاق بالموضع؛ ويمثّل كلٌّ من has_next() وnext_value() الواجهةَ كاملةً:
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(), "")الناتج:
a b c إن المولِّد هو مكرّر يحسب كل قيمة عند طلبها، ولذلك لا يتعيّن أن يكون التسلسل موجودًا في الذاكرة. ويمكن أن يكون حتى بلا نهاية:
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(), "")الناتج:
0 1 1 2 3 5 8 13 21 34 يخفي المُكرّر البنية. تخرج النتائج المخزّنة في صفحات، بعضها فارغ، كتسلسل مسطّح واحد:
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(), "")الناتج:
a b c تعمل الأدوات المساعدة المكتوبة وفقًا للواجهة مع كل مُكرِّر. تستخرج take(it, n) ما يصل إلى n من القيم، من متجه أو مولِّد أو أي شيء آخر يحتوي على has_next() و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))الناتج:
[1] 1 2
[1] 3 4 5التحدي
سهلأكمل Iterator.R:
make_iterator(x): مكرّر على عناصر متجه، معhas_next()وnext_value()؛make_range(from, to, by): مولّد للقيمfromوfrom + by... حتىtoبشكل شامل، مع حساب كل قيمة على حدة؛take(it, n): ما يصل إلىnمن القيم التالية لأي مكرّر.
يقرأ الكود المزوّد الأسطر range 1 10 3 take 2 5 (from وto وby، ثم أحجام كل عملية take) أو list a,b,c take 2 2، ويطبع ما تُرجعه كل عملية take().
ضع الكود الخاص بك في Iterator.R. يحتوي main.R على كود الإدخال/الإخراج المزوّد ولا يمكن تعديله.
جرّب بنفسك
source("Iterator.R")
# كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
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 = "")
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات S3
التعامل مع الملفاتالقوائم باستخدام فئةدوال المُنشئأساليب الطباعة والتنسيقأدوات التحقق والمساعدةمراجعة - درجات الحرارة2S3 الدوال العامة والطرق
الدوال العامة وUseMethodالطرق الافتراضيةطرق الدوال العامة الأساسيةأساسيات NextMethodمراجعة - مساحات الأشكالتدرّب بنفسك: مترجم R عبر الإنترنت