是否有一个R等同于Mathematica的Sow和Reap功能用于构建列表?

时间:2014-09-07 01:25:05

标签: r wolfram-mathematica list-manipulation

Mathematica有一个interesting way of incrementally building a list(或多个列表)的结果,您可以在复杂计算的各个点进行计算。我想在R中做类似的事情。

在Mathematica中,您可以通过将整个计算包含在Sow函数的调用中来收集计算期间每次调用Reap函数的每个参数的列表。 R是否具有这些功能的等价物?您是否可以使用环境和<<-运算符来模拟它,或者范围规则是否允许它?

修改:这是一个人为的例子。假设我想生成一个多维数据集的总和,但我还想收集我用来制作多维数据集总和的数字的平方。我知道可能有更多惯用的方法来进行这种精确的计算,但它代表了在收集沿途产生的各种物品时获得最终答案。

reap(sum(sapply(1:100, function(i) { sow(squares = i * i); i * i * i }))

我希望这会返回一些具有多维数据集加上一个命名变量&#34; square&#34;包含正方形列表。

1 个答案:

答案 0 :(得分:6)

我还没有对此进行过彻底的测试,但它似乎适用于您的简单示例。在这里,我们定义reapsow

reap <- function(...) {
    expr <- substitute(...)
    REAPENV <- new.env()
    parent.env(REAPENV) <- parent.frame()
    x <- eval(expr, REAPENV)
    c(list(x), as.list(REAPENV))
}

sow <- function(...) {
    expr <- substitute(alist(...))[-1]
    for( f in rev(sys.frames())) {
        if(exists("REAPENV", envir=f)) {
            re <- get("REAPENV", envir=f)
            if (is.null(names(expr))) {
                names(expr) <- if(length(expr)==1) {"sow"} else {letters[1:length(expr)]}
            }
            stopifnot(all(nchar(names(expr))!=0))
            for(n in names(expr)) {
                sx <- eval(expr[[n]], parent.frame())
                cv <- if(exists(n, envir=re, inherits=FALSE)) {get(n, envir=re)} else {list()}
                if(length(cv)>0) {
                    assign(n, append(cv, sx), envir=re)
                } else {
                    assign(n, sx, envir=re)
                }
            }
            break;
        }
    }
    invisible(NULL)
}

因此reap()函数基本上只定义一个新环境并在该上下文中调用它的参数。 sow函数接受命名参数列表,并评估它的参数并分配到最近的封闭“reap”环境。最后,reap()将返回一个列表,其中包含作为第一个元素传递的表达式的“自然”返回值,然后它将添加与sow()调用期间使用的名称对应的命名元素。所以,如果你运行

reap(sum(sapply(1:5, function(i) { sow(squares=i * i); i * i * i; })))

你得到了

[[1]]
[1] 225

$squares
[1]  1  4  9 16 25

正如我所提到的,这似乎适用于简单的测试用例。我确信可以改进寻找和分配正确的工作收割环境。但这至少可以提供一个起点,如果你想追求这样的事情。