23

I would like to convert a string that I pass in a function into an object (or column name).

I know that this works:

df <- data.frame(A = 1:10, B = 11:20)

test.function <- function(x)            
{
  z <- df[[x]]
  return(z)
}
test.function("A")

I don't want to use the [[.]] operator, because sometimes it is unpractical or even not applicable. I am interessted in a general method to convert a string into an "object". Therefore I tried the following:

df <- data.frame(A = 1:10, B = 11:20)

test.function <- function(x)
{
  z <- get(paste("df$", x, sep = ""))
  return(z)
}
test.function("A")

or

df <- data.frame(A = 1:10, B = 11:20)

test.function <- function(x)
{
  z <- as.name(paste("df$", x, sep = ""))
  return(z)
}
test.function("A")

or

df <- data.frame(A = 1:10, B = 11:20)

test.function <- function(x)
{
  z <- df$as.name(x)
  return(z)
}
test.function("A")

I also tried to play around with the parse, do.call and eval functions. Unfortunatelly I failed

MByD
  • 135,866
  • 28
  • 264
  • 277
Hagen Brenner
  • 803
  • 3
  • 9
  • 15

5 Answers5

33

The trick is to use parse. For instance:

> x <- "A"
> eval(parse(text=paste("df$", x, sep = "")))
 [1]  1  2  3  4  5  6  7  8  9 10

See also this Q/A: Evaluate expression given as a string

Community
  • 1
  • 1
John Colby
  • 22,169
  • 4
  • 57
  • 69
  • 1
    If the answer is parse() you should usually rethink the question. —Thomas Lumley R-help (February 2005) -- PS, i upvoted because I can't think of a better way either :) – JD Long Nov 19 '11 at 20:55
  • @JDLong Yea regular indexing by column name with `[` is always sufficient for me. Then you can take one column, or 2, or whatever... – John Colby Nov 19 '11 at 21:15
7

I just got an upvote which brought me back after 5 years to this question. I still think that the correct answer is [[ despite the OP's request not to use it, but here's a way to dress up [[ as a more functional "function".

df <-     structure(list(x = 1:3, y = 1:3), .Names = c("x", "y"), row.names = c(NA, 
-3L), class = "data.frame")

 test.function <- `[[`    # So simple, `test.function` now has all the features desired.
 df
 x y
 1 1
 2 2
 3 3
 test.function(df, "x")
#[1] 1 2 3

Or if it were desireable to hard code pulling an object named 'df' from the calling environment, a proposition that seems of dubious safety:

 test.df_txt <- function(var, dfn ='df' ){ get(dfn)[[var]] }
 test.df_txt("x")
#[1] 1 2 3

Original response (still not recommended):

You can sidestep around the limitations of "$" if you are willing to use eval(parse(text=...)) :

 test.function <- function(x)  {
   z <- eval(parse( text=paste("df$", x, sep = "")), env=.GlobalEnv)
   return(z)
   }
test.function("A")
# [1]  1  2  3  4  5  6  7  8  9 10

BUT ... it is much better to use "[[". (My initial efforts at eval(parse()-ing were stuck at not knowing enough to use the "text" argument to parse.)

IRTFM
  • 258,963
  • 21
  • 364
  • 487
4

In addition to eval(parse(text=YOUR_STRING)), you can use as.symbol as a potential alternative.

David C.
  • 1,974
  • 2
  • 19
  • 29
1

You can create a variable name from a string using the assign operator, as in: assign("a_string", NULL)

fpt
  • 358
  • 3
  • 11
1

The function call nicely does what you want like this:

x <- data.frame(a = c(TRUE, FALSE, NA), b = 1:9, c = dnorm(-4:4), d = exp(-4:4 * 1i), `syntaxically invalid name` = LETTERS[1:9], check.names = FALSE)


solution <- function (string)
eval(call(name = "$", quote(x), as.symbol(string)))


print(solution("a"))
print(solution("syntaxically invalid name"))

If you wanted to be able to specify the name of the object you're retrieving the column from, try:

x <- data.frame(a = c(TRUE, FALSE, NA), b = 1:9, c = dnorm(-4:4), d = exp(-4:4 * 1i), `syntaxically invalid name` = LETTERS[1:9], check.names = FALSE)
y <- x
y$b <- y$b * 2L


solution <- function (object.name, string)
eval(call(name = "$", as.symbol(object.name), as.symbol(string)))


print(solution("x", "b"))
print(solution("y", "b"))
Iris
  • 377
  • 2
  • 7