我想在项目中编写自定义迭代器。我可以从头开始这样做,但我更喜欢以标准方式执行此操作,因此其他人更容易阅读代码。 iterators
包似乎是迭代器的标准方法,是使用S3编写的。不幸的是,我对S3对象没有太多的专业知识(特别是在S4对象框架中如何使用S3对象的部分)。
我计划编写的迭代器将支持hasNext
方法来评估下一次迭代是否可行,以及其中一些reset
,它会将迭代重置为开头。
根据插图,iterators
中定义的“标准”迭代器没有此功能,因此我需要提供它。
问题:我的方案中的最佳做法是什么?
setOldClass
有关)使它们与S3兼容。 显然,看到一些与自定义方法兼容的foreach
- 兼容的S4迭代器示例会很高兴,但至少请给我一个指导,我可以投入精力来解决我的问题。
答案 0 :(得分:3)
在iforever
中的vignette("writing", package="iterators")
迭代器之后,可以将S3类正式化为
setOldClass(c("abstractiter", "iter"))
然后创建派生类
.IForever <- setClass("IForever", contains=c("list", "abstractiter"))
使用构造函数
IForever <- function(x)
{
nextEl <- function() x
obj <- list(nextElem=nextEl)
.IForever(obj)
}
并使用
> nextElem(it)
[1] 42
> nextElem(it)
[1] 42
> unlist(as.list(it, n=6))
[1] 42 42 42 42 42 42
但是,我不确定这对你有多大帮助。迭代器使用闭包来提供状态,这部分难题由普通IForever
函数提供,而不是S4类系统的某些方面。 S4的形式主义可能导致更好定义的API,例如,在AbstractIterator基类上定义的方法,但这已经只隐含在抽象符的S3实现中。
另一个(更好的)起点是指定所需方法的参考类
.RIterator <- setRefClass("RIterator",
contains="abstractiter",
methods=list(nextElem=function() stop("not implemented")))
迭代器可以在其上实现,
LimitIterator <- setRefClass("SleepIterator",
fields=list(times="integer", .curr="integer"),
contains="RIterator",
methods=list(
initialize=function(...) initFields(..., .curr=1L),
nextElem=function() {
if (!hasNext())
stop("StopIteration")
.curr <<- .curr + 1L
invisible(NULL)
}, hasNext=function() .curr <= times))
所以
> system.time(foreach(LimitIterator(times=8L)) %do% Sys.sleep(1L))
user system elapsed
0.052 0.000 8.057
> system.time(foreach(LimitIterator(times=8L)) %dopar% Sys.sleep(1L))
user system elapsed
0.084 0.436 1.261
答案 1 :(得分:0)
我认为你应该看看itertools
包,它有很多函数来处理迭代器,但主要是S3。
但我认为编写这些功能的S4版本并不困难。
根据您的包装设计和API,您有很多选择。
更多信息here
例如,有hasNext
函数(或方法)。
require(itertools)
it <- ihasNext(1:3)
hasNext(it)
## [1] TRUE
nextElem(it); nextElem(it); nextElem(it)
## [1] 1
## [1] 2
## [1] 3
hasNext(it)
## [1] FALSE