jayb
jayb

Reputation: 565

R: Evaluate function for multiple and differently-changing arguments

I have a function with 4 arguments:

    my.function <- function(w,x,y,z){
       w + x + y + z
    }

I can give this function multiple values for z:

> my.function(1,1,1,1:5)
[1] 4 5 6 7 8

But what if I want to give the function lists of values for w,x,y and a vector of values for z, such that the function will evaluate each set of wxy.args with each element of z?

wxy.args <- list(set1 = list(w = 1.1, x = 2.1, y = 3.1),
                 set2 = list(w = 1.2, x = 2.2, y = 3.3),
                 set3 = list(w = 1.3, x = 2.3, y = 3.3))
z <- 1:5

Ideally, I would like to end up with a n x m matrix, where n = set and m = z. For that reason, I wanted to use outer(), but it doesn't seem like that is possible.

So, I guess this will involve one of the apply family or some combination of apply and do.call, but I'm struggling with it.

Thanks in advance!

Upvotes: 3

Views: 689

Answers (4)

G. Grothendieck
G. Grothendieck

Reputation: 270268

To use outer define my.function2, a version of my.function that takes z and wxy as two separate arguments, and then pass a vectorized version of it to outer:

my.function2 <- function(z, wxy) do.call(my.function, c(wxy, z))
outer(z, wxy.args, Vectorize(my.function2))

giving:

     set1 set2 set3
[1,]  7.3  7.7  7.9
[2,]  8.3  8.7  8.9
[3,]  9.3  9.7  9.9
[4,] 10.3 10.7 10.9
[5,] 11.3 11.7 11.9

Another equivalent possibility that is simpler but slightly more tedious is to write out the arguments to my.function using this version of my.function2 instead:

my.function2 <- function(z, wxy) my.function(wxy[[1]], wxy[[2]], wxy[[3]], z)

Upvotes: 1

Roland
Roland

Reputation: 132969

You can use mapply to iterate over your sets. It iterates over the list elements. I use do.call to pass the sublists to my.function:

mapply(function(...) do.call(my.function, c(list(z = z), ...)), 
   wxy.args)
#     set1 set2 set3
#[1,]  7.3  7.7  7.9
#[2,]  8.3  8.7  8.9
#[3,]  9.3  9.7  9.9
#[4,] 10.3 10.7 10.9
#[5,] 11.3 11.7 11.9

Use t to transpose the matrix if necessary.

Upvotes: 4

det
det

Reputation: 5232

library(purrr)

wxy.args %>% map(~c(.x, z = list(z))) %>%
  map(~do.call("my.function", args = .x)) %>%
  unlist() %>%
  matrix(nrow = length(wxy.args), byrow = TRUE)

gives:

     [,1] [,2] [,3] [,4] [,5]
[1,]  7.3  8.3  9.3 10.3 11.3
[2,]  7.7  8.7  9.7 10.7 11.7
[3,]  7.9  8.9  9.9 10.9 11.9

Upvotes: 1

tmfmnk
tmfmnk

Reputation: 40171

One option could be:

sapply(z, function(x) lapply(wxy.args, function(y) sum(unlist(y), x)))

     [,1] [,2] [,3] [,4] [,5]
set1 7.3  8.3  9.3  10.3 11.3
set2 7.7  8.7  9.7  10.7 11.7
set3 7.9  8.9  9.9  10.9 11.9

Upvotes: 1

Related Questions