Reputation: 20127
I want to use dplyr's case_when
function to let me dynamically choose between functions.
For example, let's say I want to choose an average function and then call it:
average = function(.data, .avg){
f = case_when(
.avg == 'mean' ~ mean,
.avg == 'median' ~ median,
)
f(.data)
}
Now, if I call this function, I get this error:
> average(c(1, 2), 'mean')
Error in value[[1]][rep(NA_integer_, m)] :
object of type 'closure' is not subsettable
I don't think I'm doing anything wrong here, but case_when
doesn't seem to want me to return a function. I could put the result of each function (e.g. mean(.data)
) on the RHS of this case_when
, but it's important that I don't evaluate any function that isn't intended. Is there a way around this, or a similarly concise way to do a switch case in R, to choose a function?
Upvotes: 2
Views: 528
Reputation: 11128
You can try this, creating a list of functions and then use the data argument while returning the function call:
average = function(.data, .avg){
list_of_funcs <- list('mean' = mean, 'median' = median)
return(list_of_funcs[[.avg]](.data))
}
class(average)
> average(c(1,2,3,4, 10), 'mean')
# [1] 4
> average(c(1,2,3,4, 10), 'median')
# [1] 3
Upvotes: 0
Reputation: 388992
You are defining two arguments for the function average
but are passing only one. I think you were trying to call average(c(1, 2), 'mean')
but this will still not fix the issue. I think case_when
cannot return functions.
Use a simple if
/else
statement.
average = function(.data, .avg){
f <- if(.avg == 'mean') mean
else if(.avg == 'median') median
f(.data)
}
Or use base R scalar alternative of case_when
i.e switch
:
average = function(.data, .avg){
f <- switch(.avg, mean = mean, median = median)
f(.data)
}
For this simple case you can also use match.fun
:
average = function(.data, .avg){
match.fun(.avg)(.data)
}
Use any one of the above function and call it with :
average(c(1, 5, 6), 'mean')
#[1] 4
average(c(1, 5, 6), 'median')
#[1] 5
Upvotes: 4