1
x <- y <- 1:5
df = data.frame(m=x,n=y)

myfun <- function(data, var) {
  library(dplyr)
   select(data, var)
}


myfun(df, m)

Error in eval(expr, envir, enclos) : object 'm' not found

kurt
  • 91
  • 7
  • Your first version I think actually works, you simply passed `select` column indices that don't exist. – joran Sep 02 '14 at 02:53
  • However, both calls don't work for me. no clue – kurt Sep 02 '14 at 02:59
  • I will repeat, you created a df with two columns and then asked for columns 1:5. – joran Sep 02 '14 at 03:34
  • @joran if change to df = data.frame(m=x,n=y), and call myfun(df, m), still error – kurt Sep 02 '14 at 03:55
  • You didn't understand my comment at all. Your first example is attempting to select nonexistent columns from your data frame. The issue is passing the vector 1:5, not the names of the columns. – joran Sep 02 '14 at 03:58
  • ...namely that you were inadvertently attempting to use select with numeric indices, rather than column names. And I was pointing out that that WILL work, I think, unless you request nonexistent columns. – joran Sep 02 '14 at 04:02
  • 1
    Best just to wait until I've done this: https://github.com/hadley/dplyr/issues/352 – hadley Sep 03 '14 at 00:48

2 Answers2

2

Richards answer makes it possible to bypass an arbitrary number of arguments. But to control each argument of such a select call separately you have to know: In select(data, m), m is not a variable which has an assigned value at this point! It is just a symbol which gets some meaning in the context of the dataframe "data". myfun(df, m) will fail as soon as the parameter m is used (which is the case in the select-call), because m has no value (or the value from the global environment, which you surely do not want!) Internally, dplyr will use the substitute function to convert it to a symbol (instead of evaluating it). After var is converted to a symbol (or a call, for e.g. selections like m:n), you can compose and evaluate a new select-call with do.call.

For your example code this implies:

x <- y <- 1:5
df = data.frame(m=x,n=y)

myfun <- function(data, var) {
  library(dplyr)
  var <- substitute(var)
  do.call('select', list(data, var))
}


myfun(df, m)

The generalization to more arguments is straight forward.

For an arbitrary number of arguments which you want to convert to symbols or calls you can use

myfun <- function(...) {
  args <- substitute(list(...))
  # Now args[i] is a symbol/call representing the i-th argument
}
Patrick Roocks
  • 3,129
  • 3
  • 14
  • 28
  • Using `do.call()` in this way is highly not recommended - it eliminates many of the advantages of dplyr because it must construct at least one (and maybe two) extra copies of the data. – hadley Sep 03 '14 at 00:48
0

select uses select.data.frame, a data frame method. The second argument to select is a ... list so that arguments can be passed to other methods. Your function uses the name var in its second argument, and because of dplyr's .() function, the base R variance function var is being passed to other functions inside select.

Long story short, change your argument names. I would go with

myfun <- function(z, ...) select(z, ...)
myfun(df, x)
myfun(df, y)

You can also use the select methods

> select.myfun <- function(.data, ...) UseMethod("select")
> myfun(df, exclude = "x")
> methods(select)[6]
[1] "select.myfun"

As a shameless plug, I'll refer you to a question I asked about ... arguments. There are two very good explanations in the answers.

Edit As requested, a look at .()

> `.`
function (..., .env = parent.frame()) 
{
    structure(as.list(match.call()[-1]), env = .env, class = "quoted")
}
<environment: namespace:plyr>

> .(x)
List of 1
 $ x: symbol x
 - attr(*, "env")=<environment: R_GlobalEnv> 
 - attr(*, "class")= chr "quoted"
Community
  • 1
  • 1
Rich Scriven
  • 97,041
  • 11
  • 181
  • 245
  • follow on that, for example, if I have two select in my function. how can I pass different args to each one. – kurt Sep 02 '14 at 03:32
  • @Scriven could you point out where .() function is. I could not find it in the dplyr documentation. Thanks – kurt Sep 02 '14 at 04:34