查找和写入环境
Finding and writing environment
我正在编写与 Python 'pop' 方法等效的 R。我知道第 99 个百分位数有一个,但我更喜欢我自己的(practice/understanding/consistency 等)。
作为参考,pop() 接受一个对象并从对象中删除第一项,同时返回它。所以
> l <- c(1,3,5)
> x <- pop(l)
> print(l)
> 3, 5
> print(x)
> 1
我正在使用 assign() 将输入对象替换为第一个值减一并从函数返回所述第一个值。
我的问题是,如何获取输入对象的环境并在 assign() 中使用该环境?
我试过使用 pryr::where()
which returns 'R_GlobalEnv' 但我不能在 assign() 中使用这个值。相反,我可以在 assign() 中工作的唯一值是 'globalenv()'.
通过手机发布,如有问题请告诉我。
您可以使用 pryr::promise_info(l)$env
来完成,但这是一件非常 un-R-like 的事情。函数不应该有副作用。
例如,
pop <- function(l) {
info <- pryr::promise_info(l)
if (!is.name(info$code))
stop("Argument expression should be a name.")
result <- l[[1]] # work on lists too
assign(as.character(info$code), l[-1], envir = info$env)
result
}
l <- c(1, 3, 5)
pop(l)
#> Registered S3 method overwritten by 'pryr':
#> method from
#> print.bytes Rcpp
#> [1] 1
l
#> [1] 3 5
由 reprex package (v0.3.0)
于 2020-08-15 创建
编辑添加:有趣的是,到目前为止,三个答案中的 none 适用于像这样的复杂情况:
f <- function(x) {
cat("The pop(x) result is", pop(x), "\n")
cat("Now x is ", x, "\n")
cat("Now l is ", l, "\n")
}
l <- c(1, 3, 5)
f(l)
@RuiBarradas 的回答给出了
The pop(x) result is 5
Now x is 1 3 5
Now l is 1 3 5
(他弹出最后一个值而不是第一个,这没什么大不了的,但是 x
和 l
都没有被修改。)
@AllanCameron 的回答给出了
The pop(x) result is 1
Now x is 3 5
Now l is 1 3 5
这可以说是正确的(x
被弹出),但我认为 l
被弹出会很好,但这似乎很棘手。
我的回答因这条消息而消失:
Error in pop(x) : Argument expression should be a name.
这似乎是一个错误:显然,无论是 x
还是 l
,它确实是一个名称。问题似乎出在 pryr::promise_info
中,其中 return 是 return 值 x
的编译代码,而不仅仅是 x
的代码。如果我通过 compiler::enableJIT(0)
关闭 JIT 编译,我会得到与 @AllanCameron 相同的结果。我不清楚如何放回适当的数量以弹出 l
而不仅仅是 x
.
下面的答案是基于这个R-Help post, function pop
with function getEnvOf
from this SO post,都适应了问题的问题。
getEnvOf <- function(what, which=rev(sys.parents())) {
what <- as.character(substitute(what))
for (frame in which)
if (exists(what, frame=frame, inherits=FALSE))
return(sys.frame(frame))
return(NULL)
}
pop <- function(x){
y <- as.character(substitute(x))
e <- getEnvOf(y)
if(length(x) > 0) {
val <- x[[length(x)]]
assign(y, x[-length(x)], envir = parent.env(e))
val
} else {
msg <- paste(sQuote(y), "length is not > 0")
warning(msg)
NULL
}
}
y <- c(1,3,5)
pop(y)
这也适用于列表。
z <- list(1, 2, 5)
pop(z)
w <- list(1, c(2, 4, 6), 5)
pop(w)
#[1] 5
pop(w)
#[1] 2 4 6
pop(w)
#[1] 1
pop(w)
#NULL
#Warning message:
#In pop(w) : ‘w’ length is not > 0
您可以在基础 R 中实现它,但不建议这样做。 R 是一种函数式语言,end-users 不期望具有副作用的函数。
pop <- function(vec)
{
vec_name <- deparse(substitute(vec))
assign(vec_name, vec[-1], envir = parent.frame())
vec[1]
}
a <- c(2, 7, 9)
a
#> [1] 2 7 9
pop(a)
#> [1] 2
a
#> [1] 7 9
pop(a)
#> [1] 7
a
#> [1] 9
由 reprex package (v0.3.0)
于 2020-08-15 创建
我正在编写与 Python 'pop' 方法等效的 R。我知道第 99 个百分位数有一个,但我更喜欢我自己的(practice/understanding/consistency 等)。 作为参考,pop() 接受一个对象并从对象中删除第一项,同时返回它。所以
> l <- c(1,3,5)
> x <- pop(l)
> print(l)
> 3, 5
> print(x)
> 1
我正在使用 assign() 将输入对象替换为第一个值减一并从函数返回所述第一个值。
我的问题是,如何获取输入对象的环境并在 assign() 中使用该环境?
我试过使用 pryr::where()
which returns 'R_GlobalEnv' 但我不能在 assign() 中使用这个值。相反,我可以在 assign() 中工作的唯一值是 'globalenv()'.
通过手机发布,如有问题请告诉我。
您可以使用 pryr::promise_info(l)$env
来完成,但这是一件非常 un-R-like 的事情。函数不应该有副作用。
例如,
pop <- function(l) {
info <- pryr::promise_info(l)
if (!is.name(info$code))
stop("Argument expression should be a name.")
result <- l[[1]] # work on lists too
assign(as.character(info$code), l[-1], envir = info$env)
result
}
l <- c(1, 3, 5)
pop(l)
#> Registered S3 method overwritten by 'pryr':
#> method from
#> print.bytes Rcpp
#> [1] 1
l
#> [1] 3 5
由 reprex package (v0.3.0)
于 2020-08-15 创建编辑添加:有趣的是,到目前为止,三个答案中的 none 适用于像这样的复杂情况:
f <- function(x) {
cat("The pop(x) result is", pop(x), "\n")
cat("Now x is ", x, "\n")
cat("Now l is ", l, "\n")
}
l <- c(1, 3, 5)
f(l)
@RuiBarradas 的回答给出了
The pop(x) result is 5
Now x is 1 3 5
Now l is 1 3 5
(他弹出最后一个值而不是第一个,这没什么大不了的,但是 x
和 l
都没有被修改。)
@AllanCameron 的回答给出了
The pop(x) result is 1
Now x is 3 5
Now l is 1 3 5
这可以说是正确的(x
被弹出),但我认为 l
被弹出会很好,但这似乎很棘手。
我的回答因这条消息而消失:
Error in pop(x) : Argument expression should be a name.
这似乎是一个错误:显然,无论是 x
还是 l
,它确实是一个名称。问题似乎出在 pryr::promise_info
中,其中 return 是 return 值 x
的编译代码,而不仅仅是 x
的代码。如果我通过 compiler::enableJIT(0)
关闭 JIT 编译,我会得到与 @AllanCameron 相同的结果。我不清楚如何放回适当的数量以弹出 l
而不仅仅是 x
.
下面的答案是基于这个R-Help post, function pop
with function getEnvOf
from this SO post,都适应了问题的问题。
getEnvOf <- function(what, which=rev(sys.parents())) {
what <- as.character(substitute(what))
for (frame in which)
if (exists(what, frame=frame, inherits=FALSE))
return(sys.frame(frame))
return(NULL)
}
pop <- function(x){
y <- as.character(substitute(x))
e <- getEnvOf(y)
if(length(x) > 0) {
val <- x[[length(x)]]
assign(y, x[-length(x)], envir = parent.env(e))
val
} else {
msg <- paste(sQuote(y), "length is not > 0")
warning(msg)
NULL
}
}
y <- c(1,3,5)
pop(y)
这也适用于列表。
z <- list(1, 2, 5)
pop(z)
w <- list(1, c(2, 4, 6), 5)
pop(w)
#[1] 5
pop(w)
#[1] 2 4 6
pop(w)
#[1] 1
pop(w)
#NULL
#Warning message:
#In pop(w) : ‘w’ length is not > 0
您可以在基础 R 中实现它,但不建议这样做。 R 是一种函数式语言,end-users 不期望具有副作用的函数。
pop <- function(vec)
{
vec_name <- deparse(substitute(vec))
assign(vec_name, vec[-1], envir = parent.frame())
vec[1]
}
a <- c(2, 7, 9)
a
#> [1] 2 7 9
pop(a)
#> [1] 2
a
#> [1] 7 9
pop(a)
#> [1] 7
a
#> [1] 9
由 reprex package (v0.3.0)
于 2020-08-15 创建