1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
library(iterators)
# This example was originally written and contributed
# by Hadley Wickham, with minor modifications by
# Revolution Analytics
# Define a hasNext generic function
hasNext <- function(obj, ...) {
UseMethod('hasNext')
}
# Define a hasNext method for the "ihasNext" class
hasNext.ihasNext <- function(obj, ...) {
obj$hasNext()
}
# This function takes an iterator and returns an iterator that supports
# the "hasNext" method. This simplifies manually calling the "nextElem"
# method of the iterator, since you don't have to worry about catching
# the "StopIteration" exception.
ihasNext <- function(it) {
it <- iter(it)
# If "it" already has a hasNext function, return it unchanged
if (!is.null(it$hasNext))
return(it)
cache <- NULL
has_next <- NA
nextEl <- function() {
if (!hasNx())
stop('StopIteration', call.=FALSE)
# Reset the "has_next" flag and return the value
has_next <<- NA
cache
}
hasNx <- function() {
# Check if you already know the answer
if (!is.na(has_next))
return(has_next)
# Try to get the next element
tryCatch({
cache <<- nextElem(it)
has_next <<- TRUE
},
error=function(e) {
if (identical(conditionMessage(e), 'StopIteration')) {
has_next <<- FALSE
} else {
stop(e)
}
})
has_next
}
obj <- list(nextElem=nextEl, hasNext=hasNx)
class(obj) <- c('ihasNext', 'abstractiter', 'iter')
obj
}
# Create a "counting" iterator that has a hasNext method
it <- ihasNext(icount(3))
# Print the values of the iterator without the need for error handling
while (hasNext(it))
print(nextElem(it))
|