将递归函数结果保存到 R 中的全局数据帧



我试图通过将递归函数的输出保存在数据框中来在基本 R 中重新创建 memoise 包的功能。我有这个函数"P",然后我做了这个"metaP"包装器,如果之前没有运行过 metaP(n(,它将运行 P(n(,然后保存 P(n( 的结果,或者它产生以前保存的输出。 我的问题是它仅适用于第一级。 如果我运行 metaP(5(,它将保存 metaP(5( 的输出,但为了得到 P(5(,它还必须计算 P(4(,并且 P(4( 的结果不会被保存。我假设它在递归环境中丢失了,但是当我尝试使用 assign 函数并将其设置为全局环境时,它仍然不起作用。

在下面的示例中,我运行 metaP 5 到 10,df 保存了 5 到 10,但它没有保存 1 到 5,其中一些必须经过计算才能得出 5 到 10 的答案。

df <- data.frame(n = 0, pn = 1)  
metaP <- function(n) {
if (!n %in% df$n) df <<- rbind(df, data.frame(n = n, pn = P(n)))
df[df$n == n, "pn"]
}
P <- function(n) {
if (n < 0) return(0)
k <- rep(1:((sqrt(24 * n + 1) + 1) / 6), each = 2) * c(1, -1)
return(sum((-1) ^ (k + 1) * sapply(n - k * (3 * k - 1) / 2, metaP)) %% 1e6)
}
sapply(5:10, metaP)
df

这里的问题有点微妙。 表达式

df <<- rbind(df, data.frame(n = n, pn = P(n)))

不明确,因为?rbind文档未定义计算要rbind()的两个参数的顺序。 看起来 R 正在计算df,然后执行递归调用,然后将该结果附加到保存的值df中。 在递归调用期间对全局变量所做的任何更改都将丢失。

要解决此问题,请将条件部分重写为

if (!n %in% df$n) {
newval <- data.frame(n = n, pn = P(n))
df <<- rbind(df, newval)
}

(我还建议在测试中添加括号,并将其写成if (!(n %in% df$n)),因为这些是相同的并不明显。 我在早些时候对这个问题的回答中对此感到困惑。 但是检查?Syntax显示%in%的优先级高于!

最新更新