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?

+3


source to share


2 answers


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

      

+1


source


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

+2


source







All Articles