首页 > 解决方案 > 如何编写一个函数来检测 R 中是否存在对象,如果不存在,则读取该名称的文件?

问题描述

我正在尝试编写一个函数,该函数既可以使用 R 中加载的对象/数据以交互方式执行,也可以作为脚本读取,如果该文件不存在,则该脚本将读取具有所提供参数名称的文件。我很接近,但我想可能是环境有问题;该函数的行为就像函数中定义了一个我无法更改的幽灵变量。

这是我到目前为止所拥有的:

test<- function(hello) {
  bye <- (as.character(substitute(hello)))
  if(!exists(bye)) {
    assign(bye, as.data.frame(read_table2(bye,col_names = FALSE)),envir= .GlobalEnv)
    if (class(hello[[1]][[1]]) == "character") {
      do.call(`rm`,list(as.character(substitute(hello)),inherits=TRUE),envir=.GlobalEnv)
      assign(bye, as.data.frame(read_table2(bye,col_names = TRUE)),envir= .GlobalEnv)
      print(sys.frame(which=0))
      print(sys.parents())
      #assign(as.character(substitute(hello)),get(bye, pos=".GlobalEnv"))
    }
  }
  #assign(as.character(substitute(hello)),get(bye))
  print(as.character(substitute(hello)))
  print(class(hello))
  print(class("hello"))
  print(hello)
  print(sys.frame(which=0))
}
test(testdata.csv)
print(testdata.csv)

注释行是我尝试过的一些不会改变任何东西的东西。所有prints 都包含在诊断程序中,并且无论对象是预加载还是刚刚读入,都应该具有相同的值。第二条if语句的想法是我第一次假设文件没有列名,所以我检查它的字符,如果有尝试用列名重新加载它。我很确定我所拥有的并不是最有效的方法,因此欢迎任何关于改进它的想法,但它似乎都有效,除非testdata.csv有列名。当它在最后打印数据 ( print(hello)) 时,仍然没有列名,即使该变量随后在全局环境中与列名testdata.csv可见。

这是上面的输出来说明:

<environment: R_GlobalEnv>
[1] 0
[1] "testdata.csv"
[1] "data.frame"
[1] "character"
   X1 X2
1   a  b
2   1  1
3   2  1
4   3  1
5   4  1
6   5  1
7   6  2
8   7  2
9   8  3
10  9  4
11 10  5
<environment: R_GlobalEnv>

   a b
1   1 1
2   2 1
3   3 1
4   4 1
5   5 1
6   6 2
7   7 2
8   8 3
9   9 4
10 10 5

我知道这有点长,所以要澄清一下,我怎样才能hello在上面的代码中指向testdata.csv在函数期间读入的全局?我不知道为什么它还没有,但事实并非如此。提前感谢您的帮助!

标签: r

解决方案


首先,两者都existsassign一个论点envir=,并且是相关的。虽然我通常不喜欢assign在大多数情况下使用,但我认为它可以安全地使用parent.frame(),这样它是安全的,并且不会在数据范围之外工作太远。

getit <- function(x, envir = parent.frame()) {
  varname <- as.character(substitute(x))
  if (!exists(varname, envir = envir)) {
    dat <- readr::read_table2(varname, col_names = FALSE)
    assign(varname, dat, envir = envir)
  }
  get(varname, envir = envir)
}

一些样本数据:

write.table(iris[1:3,], "iris.tab", col.names = FALSE, row.names = FALSE)
list.files()
# [1] "iris.tab"   "question.R"

及其执行:

ls()                       # proof that the data does not yet exist
# [1] "getit"
getit(iris.tab)
# Parsed with column specification:
# cols(
#   X1 = col_double(),
#   X2 = col_double(),
#   X3 = col_double(),
#   X4 = col_double(),
#   X5 = col_character()
# )
# # A tibble: 3 x 5
#      X1    X2    X3    X4 X5          
#   <dbl> <dbl> <dbl> <dbl> <chr>       
# 1   5.1   3.5   1.4   0.2 "\"setosa\""
# 2   4.9   3     1.4   0.2 "\"setosa\""
# 3   4.7   3.2   1.3   0.2 "\"setosa\""
ls()
# [1] "getit"    "iris.tab"

如果对象存在,它更喜欢本地副本,而不是从文件中读取:

iris.tab[1,1] <- 999
iris.tab
# # A tibble: 3 x 5
#      X1    X2    X3    X4 X5          
#   <dbl> <dbl> <dbl> <dbl> <chr>       
# 1 999     3.5   1.4   0.2 "\"setosa\""
# 2   4.9   3     1.4   0.2 "\"setosa\""
# 3   4.7   3.2   1.3   0.2 "\"setosa\""
getit(iris.tab)
# # A tibble: 3 x 5
#      X1    X2    X3    X4 X5          
#   <dbl> <dbl> <dbl> <dbl> <chr>       
# 1 999     3.5   1.4   0.2 "\"setosa\""
# 2   4.9   3     1.4   0.2 "\"setosa\""
# 3   4.7   3.2   1.3   0.2 "\"setosa\""
readLines("iris.tab")[1]              # file is unchanged
# [1] "5.1 3.5 1.4 0.2 \"setosa\""

即使文件不存在但数据存在,它也可以工作:

mt <- mtcars
head(getit(mt))
#                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
# Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
# Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
# Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
# Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
# Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
# Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
ls()
# [1] "getit"    "iris.tab" "mt"      
list.files()
# [1] "iris.tab"   "question.R"

当对象和数据不存在时,显然会失败:

getit(foo.csv)
# Error: 'foo.csv' does not exist in current working directory ('C:/Users/r2/StackOverflow/15997184/67753553').

(您可能会选择try捕获该错误并引出一些更符合上下文的内容,例如“文件和对象都不存在......”,交给您。)


推荐阅读