r - 如何编写一个函数来检测 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)
注释行是我尝试过的一些不会改变任何东西的东西。所有print
s 都包含在诊断程序中,并且无论对象是预加载还是刚刚读入,都应该具有相同的值。第二条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
在函数期间读入的全局?我不知道为什么它还没有,但事实并非如此。提前感谢您的帮助!
解决方案
首先,两者都exists
取assign
一个论点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
捕获该错误并引出一些更符合上下文的内容,例如“文件和对象都不存在......”,交给您。)
推荐阅读
- join - 尝试从性能良好的表中获取数据
- javascript - 重新初始化 Appwork 主题事件监听器
- html - 在 xaringan 幻灯片中嵌入传单地图的问题
- google-analytics - 信用卡付款追踪
- python - pandas pd.read_excel 将所有内容放入一列
- dataframe - 如何获取火花数据框中每列的空单元格数
- java - 使用 SuperBuilder 使用 Lombok 扩展父类
- java - 使用从未在方法主体中抛出的 throws 子句声明检查的异常
- vue.js - Vue x 模块命名空间
- java - MongoDB Java驱动程序〜“类包含尚未专门化的泛型类型。” - 不包含泛型类型的类错误