Passing arguments to a function via list and ignoring unused arguments

456 views Asked by At

Background

I'm interested in using do.call to pass arguments to two functions with use of one list. The do.call solution should ignore unused arguments.

Example

my_sum <- function(a, b) {
    a + b
}

my_exp <- function(c, d) {
    c^d
}

args_to_use <- as.list(1:4)
names(args_to_use) <- letters[1:4]

my_wrapper <- function(fun_args = args_to_use) {
    res_one <- do.call(my_sum, fun_args)
    res_two <- do.call(my_exp, fun_args)
    res_one + res_two
}

Naturally, the example fails as superfluous arguments are passed to both functions.

Desired results

my_wrapper_two <- function(fun_args = args_to_use) {
    res_one <- do.call(my_sum, fun_args[1:2]) # Only a, b
    res_two <- do.call(my_exp, fun_args[3:4]) # Only c, d
    res_one + res_two
}
my_wrapper_two()
# 84

Sought solution

I would like for the subsetting operations [1:2] and [3:4] to be performed automatically depending on the function arguments.


Notes

One approach I was thinking of would be using names(formals(my_exp)) to create desired list of arguments as in:

my_wrapper_three <- function(fun_args = args_to_use) {
    res_one <- do.call(my_sum, fun_args[names(formals(my_sum))])
    res_two <- do.call(my_exp, fun_args[names(formals(my_exp))])
    res_one + res_two
}
my_wrapper_three()

This doesn't look elegant and I'm wondering if there is a more intelligent solution?

Update

The solution I cam up with is as follows:

do_call_on_existing <- function(fun, args_list) {
    fun_args <- names(formals(fun))
    viable_args <- args_list[fun_args]
    viable_args <- Filter(Negate(is.null), viable_args)
    do.call(fun, viable_args)
}

The Filter / Negate bit prevents function from failing where my_sum could have extra arguments that would result in arguments list returning null element. So the code can work:

my_sum <- function(a = 999, b = 999, c = 999) {a + b + c}
my_nms <- list(a = 1, b = 2) 
do_call_on_existing(my_sum, my_nms)
1

There are 1 answers

3
ekoam On BEST ANSWER

Try this (... allows you to pass any number of arguments into my_sum but only a and b are used as per your definition):

my_sum <- function(a, b, ...) {
    a + b
}

my_exp <- function(c, d, ...) {
    c^d
}

args_to_use <- as.list(1:4)
names(args_to_use) <- letters[1:4]

my_wrapper <- function(fun_args = args_to_use) {
    res_one <- do.call(my_sum, fun_args)
    res_two <- do.call(my_exp, fun_args)
    res_one + res_two
}