2014-12-19 5 views
3

У меня есть следующий список:декартово произведение, как в списке

lst = list(
    cat = c("room","shower","garden"), 
    dog = c("street", "garden") 
) 

И я бы получить выход:

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" 
    ) 
) 

На данный момент, я использую следующий код:

library(plyr) 

grasp <- function(animal, places) 
{ 
    llply(places, function(u) list(animal=animal, place=u)) 
} 

Reduce(append, Map(grasp, names(lst), lst)) 

Но может быть что-то более элегантное/лаконичное/новее?

+1

Я думаю, что ваш текущий метод довольно хорошо –

ответ

1

Я не знаю, если это более элегантно или кратким, и я предполагаю, что это не новый, но, тем не менее, это может быть еще один способ получения результатов:

unlist(lapply(names(lst),function(x){ 
          lapply(lst[[x]],function(y,x){ 
               list(animal=x,place=y) 
               },x=x) 
           }),recursive=F) 

Я протестированные мое решение и ваш метод plyr на списке с 1000 «животных» и 50 «мест» для каждого «животного» (I попробовал больше, но это слишком долго на моем компьютере ...), и вот Результаты (я не сделал тест метода magrittr, потому что я получил ошибку с моим списком «фиктивного»):

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 
+0

интересно! Мой метод более функциональный, но гораздо медленнее! Я предполагаю, что разница заключается в том, что я использую Map и Reduce, тогда как вы используете только один цикл lapply и unlist (мы используем один и тот же внутренний цикл!) Thumbs up! –

+0

@ColonelBeauvel, спасибо :-). Должен сказать, я был немного удивлен результатами тестов ;-), но вы должны быть правы! – Cath

2

Это довольно близко к тому, что делает функция expand.grid; однако это возвращает data.frame (который вы можете использовать вместо этого). Но вы преобразовать в список списков data.frames с

# library(magrittr) 
do.call(`expand.grid`, c(lst,stringsAsFactors = FALSE)) %>% split(., 1:nrow(.)) 

, который должен вести себя так, как вы были после

Смежные вопросы