Combination of expand.grid and mapply?

I am trying to find a variant of mapply (call it xapply ) that combines the functionality (view) of expand.grid and mapply . That is, for the FUN function and the argument list L1 , L2 , L3 , ... of unknown length, it must create a list of length n1*n2*n3 (where ni is the length of list i ), which is the result of applying FUN to all combinations of list elements.

If expand.grid worked to generate lists of lists, rather than data frames, you could use it, but I mean that lists can be lists of things that won't necessarily fit into a data frame.

This function works fine if there are exactly three lists for the extension, but I'm interested in learning about a more general solution. ( FLATTEN not used, but I can imagine that FLATTEN=FALSE will generate nested lists, not one list ...)

 xapply3 <- function(FUN,L1,L2,L3,FLATTEN=TRUE,MoreArgs=NULL) { retlist <- list() count <- 1 for (i in seq_along(L1)) { for (j in seq_along(L2)) { for (k in seq_along(L3)) { retlist[[count]] <- do.call(FUN,c(list(L1[[i]],L2[[j]],L3[[k]]),MoreArgs)) count <- count+1 } } } retlist } 

edit: forgot to return the result. One could solve this by compiling a list of indexes with combn and from there ...

+8
r lapply
source share
1 answer

I think I have a solution to my own question, but maybe someone can do better (and I did not implement FLATTEN=FALSE ...)

 xapply <- function(FUN,...,FLATTEN=TRUE,MoreArgs=NULL) { L <- list(...) inds <- do.call(expand.grid,lapply(L,seq_along)) ## Marek suggestion retlist <- list() for (i in 1:nrow(inds)) { arglist <- mapply(function(x,j) x[[j]],L,as.list(inds[i,]),SIMPLIFY=FALSE) if (FLATTEN) { retlist[[i]] <- do.call(FUN,c(arglist,MoreArgs)) } } retlist } 

edit . I tried the @baptiste suggestion, but it is not easy (or not for me). The closest I got

 xapply2 <- function(FUN,...,FLATTEN=TRUE,MoreArgs=NULL) { L <- list(...) xx <- do.call(expand.grid,L) f <- function(...) { do.call(FUN,lapply(list(...),"[[",1)) } mlply(xx,f) } 

which still does not work. expand.grid really more flexible than I thought (although it creates a strange data frame that cannot be printed), but enough magic happens inside mlply that I cannot get it to work.

Here is a test case:

 L1 <- list(data.frame(x=1:10,y=1:10), data.frame(x=runif(10),y=runif(10)), data.frame(x=rnorm(10),y=rnorm(10))) L2 <- list(y~1,y~x,y~poly(x,2)) z <- xapply(lm,L2,L1) xapply(lm,L2,L1) 
+2
source share

All Articles