从函数中将多个对象分配给 .GlobalEnv

Posted

技术标签:

【中文标题】从函数中将多个对象分配给 .GlobalEnv【英文标题】:Assign multiple objects to .GlobalEnv from within a function 【发布时间】:2012-04-01 08:56:43 【问题描述】:

一天前在这里的一篇文章让我想知道如何从一个函数中为全局环境中的多个对象分配值。这是我使用lapply 的尝试(assign 可能比<<- 更安全,但我从未真正使用过它,也不熟悉它)。

#fake data set
df <- data.frame(
  x.2=rnorm(25),
  y.2=rnorm(25),
  g=rep(factor(LETTERS[1:5]), 5)
)

#split it into a list of data frames
LIST <- split(df, df$g)

#pre-allot 5 objects in R with class data.frame()
V <- W <- X <- Y <- Z <- data.frame()

#attempt to assign the data frames in the LIST to the objects just created
lapply(seq_along(LIST), function(x) c(V, W, X, Y, Z)[x] <<- LIST[[x]])

请随意缩短我的代码的任何/所有部分以使这项工作(或工作得更好/更快)。

【问题讨论】:

这个问题或任何答案都应该伴随着一句“孩子们,不要在家里做这个!”免责声明。您可能知道,函数中的全局分配是灾难的根源,或者引用 Richard Burns (burns-stat.com/pages/Tutor/R_inferno.pdf) 的话来说是“火山旁的生活” @flodel 我不是程序员,所以你能简单解释一下分配的问题吗? 我将引用***关于全局变量的内容:由于它们的非局部性,它们通常被认为是不好的做法:全局变量可以从任何地方修改(除非它们驻留在受保护的内存中或以其他方式呈现为只读),并且程序的任何部分都可能依赖于它。 [1]因此,全局变量具有创建相互依赖关系的无限潜力,而添加相互依赖关系会增加复杂性。 好的...通过更好地了解您的特定情况,您似乎并没有偏离您的全球环境太远,因此“相互依赖”的风险在这里非常小,乔希的回答很好。尽管如此,我希望我的警告可以帮助其他可能试图“在一个函数内将多个对象分配给 .GlobalEnv”(您的问题标题)但在更复杂的上下文中的人。 我得说,当涉及到复杂/脏数据时,为一组 a不编程的人,这是将他们带入计划的好方法,而无需对他们进行编程培训。 【参考方案1】:

2018-10-10 更新:

执行此特定任务的最简洁方法是使用list2env(),如下所示:

## Create an example list of five data.frames
df <- data.frame(x = rnorm(25),
                 g = rep(factor(LETTERS[1:5]), 5))
LIST <- split(df, df$g)

## Assign them to the global environment
list2env(LIST, envir = .GlobalEnv)

## Check that it worked
ls()
## [1] "A"    "B"    "C"    "D"    "df"   "E"    "LIST"

原始答案,演示了assign()的用法

你说得对,assign() 是适合这项工作的工具。它的envir 参数让您可以精确控制分配发生的位置——&lt;-&lt;&lt;- 都没有这种控制。

因此,例如,要将 X 的值分配给全局环境中名为 NAME 的对象,您可以这样做:

assign("NAME", X, envir = .GlobalEnv)

在你的情况下:

df <- data.frame(x = rnorm(25),
                 g = rep(factor(LETTERS[1:5]), 5))
LIST <- split(df, df$g)
NAMES <- c("V", "W", "X", "Y", "Z")

lapply(seq_along(LIST), 
       function(x) 
           assign(NAMES[x], LIST[[x]], envir=.GlobalEnv)
        
)

ls()
[1] "df"    "LIST"  "NAMES" "V"     "W"     "X"     "Y"     "Z"    

【讨论】:

谢谢。我知道&lt;&lt;- 是不好的形式,但一直很懒惰。我会养成使用assign 的习惯。实际上,我确实有你在某一时刻所做的事情,但我认为我不应该在对象周围加上引号,因为我已经预先分配了它们。无论如何,这更容易。 是的。使用assign() 是在尝试之前似乎很难克服的事情之一,但是一旦你这样做了,你就会想知道为什么你一开始会犹豫不决。 +1 - 金。刚才我不得不将一个环境中的所有对象都分配到全局环境中,这个解决方案让我不必再考虑了。 什么时候应该使用 envir=.GlobalEnv 以及什么时候应该使用 envir=parent.frame()?【参考方案2】:

如果您有对象名称和文件路径列表,您也可以使用mapply

object_names <- c("df_1", "df_2", "df_3")
file_paths   <- list.files(path, pattern = ".csv", full.names = T)
    
mapply(function(df_name, file) 
           assign(df_name, read.csv(file), envir=.GlobalEnv),
       object_names,
       file_paths)
我使用list.files() 构造了一个包含所有 .csv 文件的向量 具体目录。但是 file_paths 可以以任何方式编写或构造。 如果您要读取的文件在当前工作 目录,然后 file_paths 可以替换为字符向量 文件名。 在上面的代码中,您需要将 path 替换为 所需目录路径的字符串。

【讨论】:

以上是关于从函数中将多个对象分配给 .GlobalEnv的主要内容,如果未能解决你的问题,请参考以下文章

如何在sql服务中将列名分配给标量函数的返回值

js从一个函数重新分配一个值给多个已经声明的变量[重复]

如何在kotlin中将lambdas与函数式接口一起使用并直接将lambda分配给var

从函数调用分配多个返回值的性能[重复]

在 C# 中将字符串文字分配给字符串

在 C++ 中将派生类对象分配和访问到基类“指向指针”对象