Menu
Coddy logo textTech

이터레이터 패턴

Coddy R 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 49번째.

이터레이터는 컬렉션의 항목을 한 번에 하나씩 제공하므로, 이를 사용하는 코드는 컬렉션이 어떻게 저장되는지 알 필요가 없습니다. 클로저가 위치를 유지하며, 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)은 벡터, 제너레이터 또는 has_next()와 next_value()를 가진 그 밖의 모든 것에서 최대 n개의 값을 가져옵니다:

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
challenge icon

챌린지

쉬움

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 = "")
  }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 R 컴파일러