【问题标题】:Compiling a vector from a recursive function in R从 R 中的递归函数编译向量
【发布时间】:2021-01-08 06:02:15
【问题描述】:

我正在尝试了解作用域在 R 中的递归函数中是如何工作的。

上下文是这个函数,它应该返回向量元素的所有唯一组合。 (确切的期望输出的细节在这里并不真正相关。)

perm <- function(x) {
    n <- length(x)
    if (n == 1) {
        print(x)
    } else {
        y <- NULL
        for (i in 1:n) {
            y <- paste(x[i], perm(x[-i]), sep = "_")
        }
        print(y)
    }
}

当我打印我知道我想要返回的对象(此处为 print(x) 和 print(y))时,我会得到正确的值作为打印输出返回到控制台:

perm(c("a","b","c"))

但是,当我尝试将这些元素收集到一个向量中时,生成的向量包含的元素数量比打印出来的要多很多。我怀疑这与递归有关,但考虑到 print 函数只是被明智地触发,这似乎很奇怪。例如,使用全局变量来跟踪输出以忽略任何范围问题:

out <- c()
perm <- function(x) {
    n <- length(x)
    if (n == 1) {
        assign('out', c(out, x), envir = .GlobalEnv)
    } else {
        y <- NULL
        for (i in 1:n) {
            y <- paste(x[i], perm(x[-i]), sep = "_")
        }
        assign('out', c(out, y), envir = .GlobalEnv)
    }
}

perm(c("a","b","c"))
out

第一个示例仅打印 10 个值,而在第二个示例中,out 的长度为 56,并且包含第一个示例中未找到的值(例如,"c_c")。我知道以这种方式分配向量的效率非常低,但我只是想弄清楚范围如何工作以及为什么这些结果如此不同。我不会想到 print 函数会有任何范围问题,即每次触发 print(x) 或 print(y) 时,我都希望输出打印到控制台。

当我将out 分配给父框架而不是全局环境时,也会发生同样的事情,即out &lt;&lt;- c(out, x)。有趣的是,如果我只使用print 语法,我可以轻松计算大量组合;但是当使用向量赋值时,超过四个元素的任何东西都会导致递归混乱,从而炸毁系统。

所以我猜问题是,

  1. 为什么当print 函数在同一个地方被调用时,它似乎更频繁地触发向量分配?

  2. 有没有更好的方法来实现这种功能?

perm 函数基于 this blog post 中的函数之一。

【问题讨论】:

  • 如果n &gt; 1,你的第一个函数返回y(因为那是print不可见的返回)。在同样的情况下,您的第二个函数返回 out (因为这是 assign 隐形返回的内容)。返回值在递归中很重要。我建议明确使用 return 函数,直到您获得更好的理解为止。

标签: r recursion scope


【解决方案1】:
  1. 为什么在同一个地方调用它们时,它似乎比打印函数更频繁地触发向量分配?

问题是print 返回第一个参数,而assign 返回分配的值。采取:

b <- assign("a", 2)
b
#R> [1] 2

因此,您的功能应该是:

out <- c()
perm <- function(x) {
  n <- length(x)
  if (n == 1) {
    assign('out', c(out, x), envir = .GlobalEnv)
    x
  } else {
    y <- NULL
    for (i in 1:n) {
      y <- paste(x[i], perm(x[-i]), sep = "_")
    }
    assign('out', c(out, y), envir = .GlobalEnv)
    y
  }
}

perm(c("a","b","c"))
#R> [1] [1] "c_b_a"
out
#R> [1] "c"     "b"     "c_b"   "c"     "a"     "c_a"   "b"     "a"     "b_a"   "c_b_a"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-05
    • 1970-01-01
    • 2020-12-13
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    相关资源
    最近更新 更多