r - 从 R 中的递归函数编译向量
问题描述
我试图了解范围如何在 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
第一个示例仅打印十个值,而在第二个示例中,out
长度为 56 并包含第一个示例中未找到的值(例如,"c_c"
)。我知道以这种方式分配向量效率非常低,但我只是想弄清楚范围如何工作以及为什么这些结果如此不同。我不会想到该功能会有任何范围问题print
,即,每次print(x)
或被print(y)
触发时,我都希望输出打印到控制台。
当我分配out
给父框架而不是全局环境时,也会发生同样的事情,即out <<- c(out, x)
. 有趣的是,如果我只使用print
语法,我可以很容易地计算出大量的组合;但是当使用向量赋值时,超过四个元素的任何东西都会导致递归混乱,从而破坏系统。
所以我想问题是,
为什么
print
在同一个地方调用它们时,它似乎比函数更频繁地触发向量分配?有没有更好的方法来实现这种功能?
该perm
功能基于此博客文章中的功能之一。
解决方案
- 为什么当它们在同一个地方被调用时,它似乎比 print 函数更频繁地触发向量分配?
问题是在返回赋值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"
推荐阅读
- jmeter - jmeter v5 上的 Apache jmeter 仪表板报告显示 1 个用户的不同最小值和最大值,但运行次数不同
- amazon-web-services - 如何在您拥有的所有 S3 存储桶中找到最大的文件
- c# - C#如何将变量访问作为表达式或文本传递
- java - 所有@Operation 的@Extensions
- amazon-web-services - 如何仅使用 API 网关编写 serverless.yml(无资源)
- javascript - crypto.createHash() 创建安全热点
- c# - 如何统一通过非静态类传递游戏对象
- ios - iOS 应用无法接收来自 Firebase 的通知
- json - Amazon S3 json 文件到 BigQuery
- mysql - NestJS Typeorm 保存一对多关系