Frederick
Frederick

Reputation: 850

passing more than one argument to FUN of lapply

My question builds on a another, similar question: passing several arguments to FUN of lapply (and others *apply)

I have a custom function creating a data.frame. The goal is to retrieve a list of data.frames for each new input variable (I want to sort of loop over several input variables to create new data.frames).

I manage to do want I want if only one input variable is changing:

fn <- function(a, b){
        data.frame(res = c(a, b, a + b),
                   text = c("a", "b", "total"))
}
fn(1, 2)
#>   res  text
#> 1   1     a
#> 2   2     b
#> 3   3 total

lapply(1:3, FUN = fn, b = 1)
#> [[1]]
#>   res  text
#> 1   1     a
#> 2   1     b
#> 3   2 total
#> 
#> [[2]]
#>   res  text
#> 1   2     a
#> 2   1     b
#> 3   3 total
#> 
#> [[3]]
#>   res  text
#> 1   3     a
#> 2   1     b
#> 3   4 total

However, as soon as I also change the second input variable (b) I receive an error message.

lapply(1:3, FUN = fn, b = 1:3)

Error in data.frame(res = c(a, b, a + b), text = c("a", "b", "total")): arguments imply differing number of rows: 7, 3

A suggested approach in the question above (see link) is to use mapply. This works, but returns a matrix which I interpret as a list of lists (please correct me if I am wrong).

x <- mapply(fn, b = 1:3, a = 1:3)
x
#>      [,1]      [,2]      [,3]     
#> res  Integer,3 Integer,3 Integer,3
#> text factor,3  factor,3  factor,3

To get my desired list of data.frames I could again use apply:

apply(x, 2, data.frame)
#> [[1]]
#>   res  text
#> 1   1     a
#> 2   1     b
#> 3   2 total
#> 
#> [[2]]
#>   res  text
#> 1   2     a
#> 2   2     b
#> 3   4 total
#> 
#> [[3]]
#>   res  text
#> 1   3     a
#> 2   3     b
#> 3   6 total

Created on 2019-05-22 by the reprex package (v0.2.1)


Question: is there a way to avoid mapply followed by apply to set more than one input variable in a custom made function?

Upvotes: 0

Views: 446

Answers (1)

Humpelstielzchen
Humpelstielzchen

Reputation: 6441

You can do:

library(purrr)

map2(1:3, 1:3, fn)

[[1]]
  res  text
1   1     a
2   1     b
3   2 total

[[2]]
  res  text
1   2     a
2   2     b
3   4 total

[[3]]
  res  text
1   3     a
2   3     b
3   6 total

If you wanto to stick to mapply you can do:

x <- mapply(fn, b = 1:3, a = 1:3, SIMPLIFY = F)

or

x <- Map(fn, b = 1:3, a = 1:3)

which is a wrapper for mapply with SIMPLIFY = F.

Upvotes: 2

Related Questions