20

我发现自己需要更新以前使用save. 如果我不小心加载文件,我可能会忘记在文件中重新保存一些对象。例如,我正在处理一个包含一些对象的包sysdata.rda(查找表供内部使用,我不想导出),并且只想担心更新单个对象。

我还没有弄清楚是否有标准的方法来做到这一点,所以创建了我自己的函数。

resave <- function (..., list = character(), file = stop("'file' must be specified")) {
  # create a staging environment to load the existing R objects
  stage <- new.env()
  load(file, envir=stage)
  # get the list of objects to be "resaved"
  names <- as.character(substitute(list(...)))[-1L]
  list <- c(list, names)
  # copy the objects to the staging environment
  lapply(list, function(obj) assign(obj, get(obj), stage))
  # save everything in the staging environment
  save(list=ls(stage, all.names=TRUE), file=file)
}

不过,这似乎有点矫枉过正。有没有更好/更简单的方法来做到这一点?

顺便说一句,我是否正确假设在函数范围内创建的新环境在函数调用后被销毁?

4

2 回答 2

26

Here is a slightly shorter version:

resave <- function(..., list = character(), file) {
   previous  <- load(file)
   var.names <- c(list, as.character(substitute(list(...)))[-1L])
   for (var in var.names) assign(var, get(var, envir = parent.frame()))
   save(list = unique(c(previous, var.names)), file = file)
}

I took advantage of the fact the load function returns the name of the loaded variables, so I could use the function's environment instead of creating one. And when using get, I was careful to only look in the environment from which the function is called, i.e. parent.frame().

Here is a simulation:

x1 <- 1
x2 <- 2
x3 <- 3
save(x1, x2, x3, file = "abc.RData")

x1 <- 10
x2 <- 20
x3 <- 30
resave(x1, x3, file = "abc.RData")

load("abc.RData")
x1
# [1] 10
x2
# [1] 2
x3
# [1] 30
于 2012-08-05T01:51:54.633 回答
0

我在 stackoverflow 包中添加了@flodel 答案的重构版本。它明确地使用环境来更具防御性。

resave <- function(..., list = character(), file) {
  e <- new.env()
  load(file, e)
  list <- union(list, as.character(substitute((...)))[-1L])
  copyEnv(parent.frame(), e, list)
  save(list = ls(e, all.names=TRUE), envir = e, file = file)
}
于 2015-11-01T17:48:08.110 回答