Cartesian product in a list
I have the following list:
lst = list(
cat = c("room","shower","garden"),
dog = c("street", "garden")
)
And I would get the result:
list(
list(
animal="cat",
place ="room"
),
list(
animal="cat",
place ="shower"
),
list(
animal="cat",
place ="garden"
),
list(
animal="dog",
place ="street"
),
list(
animal="dog",
place ="garden"
)
)
At the moment I am using the following code:
library(plyr)
grasp <- function(animal, places)
{
llply(places, function(u) list(animal=animal, place=u))
}
Reduce(append, Map(grasp, names(lst), lst))
But maybe something more elegant / concise / new?
source to share
I don't know if this is more elegant or succinct, and I think it is not newer, but it could still be a different way to get the results:
unlist(lapply(names(lst),function(x){
lapply(lst[[x]],function(y,x){
list(animal=x,place=y)
},x=x)
}),recursive=F)
I checked my solution and your method plyr
is listed with 1000 "animals" and 50 "places" for each "animal" (I tried more than this, but it took too long on my computer ...) and here are the results (I am not was comparing the method magrittr
because I got an error with my "dummy" list):
base_meth<-function(){unlist(lapply(names(lst),function(x){lapply(lst[[x]],function(y,x){list(animal=x,place=y)},x=x)}),recursive=F)}
plyr_meth<-function(){Reduce(append, Map(grasp, names(lst), lst))}
microbenchmark(base_meth(),plyr_meth(),unit="relative",times=500)
# Unit: relative
# expr min lq mean median uq max neval cld
# base_meth() 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 500 a
# plyr_meth() 6.885256 6.844418 5.798948 6.527788 5.475684 7.589215 500 b
source to share
This is very close to what the function does expand.grid
; however this returns data.frame (which you can use instead). But you are converting to a list of lists of data.frames with
# library(magrittr)
do.call(`expand.grid`, c(lst,stringsAsFactors = FALSE)) %>% split(., 1:nrow(.))
which should behave the way you were after
source to share