是否有任何标准方法在R中实现S4,foreach兼容的迭代器?

时间:2013-06-09 15:24:34

标签: r oop iterator s4

我想在项目中编写自定义迭代器。我可以从头开始这样做,但我更喜欢以标准方式执行此操作,因此其他人更容易阅读代码。 iterators包似乎是迭代器的标准方法,是使用S3编写的。不幸的是,我对S3对象没有太多的专业知识(特别是在S4对象框架中如何使用S3对象的部分)。

我计划编写的迭代器将支持hasNext方法来评估下一次迭代是否可行,以及其中一些reset,它会将迭代重置为开头。

根据插图,iterators中定义的“标准”迭代器没有此功能,因此我需要提供它。

问题:我的方案中的最佳做法是什么?

  • 无论如何我都喜欢在S4对象框架中创建我的迭代器并使用一些魔法(目前我不知道,但与setOldClass有关)使它们与S3兼容。
  • 也许还有另一个标准的S4兼容迭代器包,我找不到?

显然,看到一些与自定义方法兼容的foreach - 兼容的S4迭代器示例会很高兴,但至少请给我一个指导,我可以投入精力来解决我的问题。

2 个答案:

答案 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