72 lines
1.6 KiB
R
72 lines
1.6 KiB
R
|
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))
|