概括
鉴于问题细节的各种变化,这里有两种解决问题的方法,可以表述为:
给定
col_names <- c("Obj1$Var1", "Obj2$Var2")
如何返回一个相当于
cbind(Obj1$Var1, Obj2$Var2)
?
最简单的解决方案是
as.data.frame(sapply(col_names, function(x) eval(parse(text = x))))
但是这种用途parse()
不应该依赖于这样的事情。另一种但稍长的解决方案是
get4 <- function(x, ...) {
fun <- function(text, ...) {
obj <- get(text[1], ...)
obj[[text[2]]]
}
sx <- strsplit(x, "\\$")
lx <- lapply(sx, fun, ...)
out <- do.call(cbind.data.frame, lx)
names(out) <- x
out
}
get4(col_names)
第二种解决方案虽然有点长,但具有优势,因为它
- 将适用于不同类型的数据,因为它适用于列表并将其转换为数据框。该
eval(parse(text = ....))
解决方案首先简化为一个数组。使用lapply()
代替sapply()
是一个解决这个问题的选项,但需要额外的工作来更改names
结果对象的。
- 使用通用函数
get()
来获取具有指定名称和基本子集语法的对象。
- 不使用
parse
;-)
原始答案
更详细的原始答案继续如下:
eval(parse(....))
将工作
data1 <- data.frame(column1 = 1:10, column2 = letters[1:10])
txt <- "data1$column2"
> eval(parse(text = txt))
[1] a b c d e f g h i j
Levels: a b c d e f g h i j
正如@texb 所提到的,这可以简单地扩展为通过处理字符串向量(修改为返回数据帧)
col_names <- c("iris$Sepal.Length", "iris$Sepal.Width")
as.data.frame(sapply(col_names, function(x) eval(parse(text = x))))
使用它可能更容易接受,get
但你必须做一些进动,类似于
get2 <- function(x, ...) {
sx <- strsplit(x, "\\$")[[1]]
obj <- get(sx[1], ...)
obj[[sx[2]]]
}
> get2(txt)
[1] a b c d e f g h i j
Levels: a b c d e f g h i j
iris
OP的问题示例
正如@texb 提到的,该eval(parse(text = ....))
版本可以简单地扩展为通过处理字符串向量(修改为返回数据帧)
col_names <- c("iris$Sepal.Length", "iris$Sepal.Width")
as.data.frame(sapply(col_names, function(x) eval(parse(text = x))))
iris$Sepal.Length iris$Sepal.Width
1 5.1 3.5
2 4.9 3.0
3 4.7 3.2
4 4.6 3.1
5 5.0 3.6
6 5.4 3.9
....
修改get2()
也可以允许它在字符串向量上工作,例如col_names
. 在这里,我遍历 的第一个元素sx
以提取对象字符串(检查是否只有一个唯一的对象名称),然后get
是该对象,然后使用变量名称对其进行子集化(使用 提取sapply(sx, `[`, 2)
)
get3 <- function(x, ...) {
sx <- strsplit(x, "\\$")
obj <- unique(sapply(sx, `[`, 1))
stopifnot(length(obj) == 1L)
obj <- get(obj, ...)
obj[sapply(sx, `[`, 2)]
}
col_names <- c("iris$Sepal.Length", "iris$Sepal.Width")
head(get3(col_names))
> head(get3(col_names))
Sepal.Length Sepal.Width
1 5.1 3.5
2 4.9 3.0
3 4.7 3.2
4 4.6 3.1
5 5.0 3.6
6 5.4 3.9
如果您引用了多个对象,col_names
那么您将需要一个不同的解决方案,沿着
get4 <- function(x, ...) {
fun <- function(text, ...) {
obj <- get(text[1], ...)
obj[[text[2]]]
}
sx <- strsplit(x, "\\$")
lx <- lapply(sx, fun, ...)
out <- do.call(cbind.data.frame, lx)
names(out) <- x
out
}
col_names2 <- c("iris$Sepal.Length", "iris2$Sepal.Length")
get4(col_names2)
> head(get4(col_names2))
iris$Sepal.Length iris2$Sepal.Length
1 5.1 5.1
2 4.9 4.9
3 4.7 4.7
4 4.6 4.6
5 5.0 5.0
6 5.4 5.4