7

How can I pass a column name in a function similar to the question here but using dplyr chaining and filter() together with %in%.

require(dplyr)
set.seed(8)
df <- data.frame(
  A=sample(c(1:3), 10, replace=T), 
  B=sample(c(1:3), 10, replace=T))

If want to get rows where column A is 1 or 2 I can do:

df %>% filter(A %in% c(1,2))

I get:

  A B
1 2 3
2 1 2
3 1 3
4 2 1
5 1 1
6 1 3

Now, how can I put this in a function, where one can specify the column, this does not work:

fun1 <- function(x, column, n){
  res <- 
    x %>% filter(column %in% n)
  return(res)
}
fun1(df, A, c(1,2))
Community
  • 1
  • 1
user3375672
  • 3,728
  • 9
  • 41
  • 70

4 Answers4

9

You could try

fun1 <- function(x, column, n){
 x %>% 
  filter_(lazyeval::interp(quote(x %in% y), x=as.name(column), y=n))
 }
fun1(df, 'A', 1:2)

Or

fun2 <- function(x, column, n){
   args <- as.list(match.call())
   x %>%
     filter(eval(args$column, x) %in% n)
 }

 fun2(df, A, 1:2)
akrun
  • 874,273
  • 37
  • 540
  • 662
  • This is something good to see now. When I asked a similar question a while ago, @aosmith provided a nice answer. Here, I see an updated version. Today I am taking notes. :) +1 – jazzurro Feb 04 '15 at 15:31
  • @akrun could you put an explanation for your option 2 - will `match.call()` contain all arguments that is put inside the function ? And how does this become interpretable by `filter()` in `eval()` ? – user3375672 Feb 04 '15 at 17:23
  • @user3375672 Yes, match.call() contains all the arguments. Here, the dataset is the `envir` (i.e. `x`) for the column. Please check `?eval` – akrun Feb 04 '15 at 17:26
4

If you want to keep your function, try:

fun1 <- function(x, column, n){
  res <- x %>% filter_(paste(column,"%in%",n))
  return(res)
}

fun1(df, "A", "c(1,2)")
NicE
  • 21,165
  • 3
  • 51
  • 68
2

Try changing your function to

fun1 <- function(x, column, n){
    require(lazyeval)
    filter_(x,
        interp(quote(col %in% n),
            col = lazy(column), n = n))
}

all(fun1(df, A, c(1, 2)) == filter(df, A %in% c(1,2)))
# TRUE
konvas
  • 14,126
  • 2
  • 40
  • 46
0

I know this question is quite old, but stumbled across it in my search for this answer. I found something that is more simple and seems more intuitive to me. All that is required is adding double curly braces around the variable i.e. {{var}}.

fun1 <- function(x, column, n){
  res <- 
    x %>% filter({{column}} %in% n)
  return(res)
}
fun1(df, A, c(1,2))

Credit: https://www.schmidtynotes.com/blog/r/2021-12-20-pass-column-name-to-dplyr-function-in-function/