Pass string as name of attached data column name
r
Solution
Summary
In light of the various changes to the detail of the question, here are two solutions to the problem that can be phrased as:
Given
col_names <- c("Obj1$Var1", "Obj2$Var2")
how to return a data frame that would be the equivalent of
cbind(Obj1$Var1, Obj2$Var2)
?
The simplest solution would be
as.data.frame(sapply(col_names, function(x) eval(parse(text = x))))
but that uses `parse()` which shouldn't be relied on for things like this. An alternative, but somewhat longer solution is
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)
The second solution has advantages, despite being somewhat longer, in that it
- will work for data of different types as it works with a list and converts that to a data frame. The `eval(parse(text = ....))` solution simplifies to an array first. Using `lapply()` instead of `sapply()` is an option that gets round this, but needs extra work to change the `names` of the resulting object.
- uses common function `get()` to grab the object with stated name, and basic subsetting syntax.
- doesn't use `parse` ;-)
Original Answer
The original Answer with greater detail continues below:
`eval(parse(....))` will work
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
As @texb mentions, this can trivially be extended to handle a vector of strings via (modified to return a data frame)
col_names <- c("iris$Sepal.Length", "iris$Sepal.Width")
as.data.frame(sapply(col_names, function(x) eval(parse(text = x))))
It may be more acceptable to use `get` but you'll have to do a bit of precessing, something along the lines of
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` example from OP's question
As @texb mentions, the `eval(parse(text = ....))` version can trivially be extended to handle a vector of strings via (modified to return a data frame)
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
....
Modifiying `get2()` is also possible to allow it to work on a vector of strings such as `col_names`. Here I loop over the first elements of `sx` to extract the object string (checking that there is only one unique object name), then I `get` that object and then subset it using the variable names (extracted using `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
If you have multiple objects referenced in `col_names` then you will need a different solution, along the lines of
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
Problem
I know that one can pass strings as variable names using the `eval(parse())` and `as.names()` functions. But my problem is a bit different. I have a string that contains both the data and column name, for example the string: `data1$column2`. When I try the mentioned commands I get a variable not found error for the variable `data1$column2`. The variable is itself is of course called `data1` and can thus not be found as R interprets the whole string as a variable name. How do I get the $-sign working as a column reference? Some kind of paste-as-text-command would be great, too. That is, if I just could pass the string as a literal part of my console input. EXAMPLE ``` attach(iris) col_names <- cbind("iris$Sepal.Length", "iris$Sepal.Width") col_names ``` Now I want to do: ``` "as.data.frame(parse(col_names))" ``` That is, to be interpreted as: ``` as.data.frame(cbind(iris$Sepal.Length, iris$Sepal.Width)) ```