lapply() 在处理时逐步清空列表

lapply() emptied list step by step while processing

首先,请原谅我的标题不好。我仍然对这种行为感到困惑,无法描述它;但是我能够重现它并将其分解为一个(愚蠢的)示例。

拜托,你能解释一下为什么 other.list 在调用 lapply() 后看起来满是 NULL 吗?

some.list <- rep(list(rnorm(1)),33)
other.list <- rep(list(), length = 33)

lapply(seq_along(some.list), function(i, other.list) {
  other.list[[i]] <- some.list[[i]]
  browser()
}, other.list)

我在 RStudio 的调试模式下观看了这个。对于某些 iother.list[[i]] 被分配 some.list[[i]],但在下一次迭代中它将被 NULLed。我想理解这种行为太糟糕了!

原因是赋值发生在函数内部,并且您使用了普通赋值运算符 <-,而不是超赋值运算符 <<-。当在函数范围内时,IOW 当函数被执行时,普通赋值运算符总是分配给评估环境中的局部变量,该局部变量是为该函数的特定评估创建的(通过调用 environment() from inside the function with fun=NULL). Thus, your global other.list variable, which is defined in the global environment (returned by globalenv()), will not be touched by such an assignment. The superassignment operator, on the other hand, will follow the closure environment chain (can be followed recursively via parent.env() 返回)直到它在赋值的 LHS 上找到名称为该名称的变量,然后将其赋值给该变量。全局环境始终处于闭包环境链的底部。如果找不到这样的变量,超赋值运算符会在全局环境中创建一个。

因此,如果您在函数内部发生的赋值中将 <- 更改为 <<-,您将能够修改全局 other.list 变量。

参见 https://stat.ethz.ch/R-manual/R-devel/library/base/html/assignOps.html

在这里,我试着做了一个小演示来演示这些概念。在我所有的作业中,我正在分配包含分配给变量的实际环境:

oldGlobal <- environment(); ## environment() is same as globalenv() in global scope
(function() {
    newLocal1 <- environment(); ## creates a new local variable in this function evaluation's evaluation environment
    print(newLocal1); ## <environment: 0x6014cbca8> (different for every evaluation)
    oldGlobal <<- parent.env(environment()); ## target search hits oldGlobal in closure environment; RHS is same as globalenv()
    newGlobal1 <<- globalenv(); ## target search fails; creates a new variable in the global environment
    (function() {
        newLocal2 <- environment(); ## creates a new local variable in this function evaluation's evaluation environment
        print(newLocal2); ## <environment: 0x6014d2160> (different for every evaluation)
        newLocal1 <<- parent.env(environment()); ## target search hits the existing newLocal1 in closure environment
        print(newLocal1); ## same value that was already in newLocal1
        oldGlobal <<- parent.env(parent.env(environment())); ## target search hits oldGlobal two closure environments up in the chain; RHS is same as globalenv()
        newGlobal2 <<- globalenv(); ## target search fails; creates a new variable in the global environment
    })();
})();
oldGlobal; ## <environment: R_GlobalEnv>
newGlobal1; ## <environment: R_GlobalEnv>
newGlobal2; ## <environment: R_GlobalEnv>

我没有 运行 你的代码,但有两个观察结果:

  1. 我通常避免将 browser() 作为函数中的最后一行,因为它被视为 return 值

  2. other.list 不会被您的 lapply 修改。您需要了解环境的基础知识,并且您在 lapply 内部进行的任何绑定都不会在其外部成立。这是一个设计特性,重点是 lapply 不能有副作用——你应该只使用它的 return 值。您可以使用 <<- 运算符而不是 <- 尽管我不推荐这样做,或者您可以使用 assign 函数代替。或者你可以按照 lapply 的方式正确地使用它:

    others.list <- lapply(seq_along(some.list), 函数(i, other.list) { some.list[[我]] })

请注意,通常建议不要在 lapply 内部进行会更改其外部变量的赋值。 lapply 意味着对每个元素和 return 一个列表执行一个函数,该列表应该是 lapply 用于

的所有内容