EDC
EDC

Reputation: 633

Combining elements of different length from nested list

The following structure is given:

a <- list()
a[[1]] <- list(c(1:3),c(3:8))
a[[2]] <- list(c(2:6),c(7:9),c(18:24))
a[[3]] <- list(c(11:13),c(10:16),c(17:19),c(11:14),c(17:20))

That means a[[1]] has 2 elements, a[[2]] 3 elements and a[[3]] 5 elements.

I would like to create all the possible combinations from the elements within a. So for example a[[1]][1] can be combined with a[[2]][1],a[[2]][2] and a[[2]][3]. All of those results can be combined with a[[3]][1],...,a[[3]][5] (All in all it should be 30 combinations). By combining I mean applying c to the elements.

I assume this comes down to searching elements at the end of a tree (e.g. if I have A1 or A2 in phase 1, B1 or B2 in phase 2 and C1 or C2 in phase 3, all results would be: A1B1C1, A1B1C2, A1B2C1, A1B2C2, A2B1C1, A2B1C2, A2B2C1, A2B2C2.)

Ok now I know how to do this with a triple nested loop, but what happens if list a becomes larger? I don't know if it can be done otherwise though. Any suggestions appreciated.

Upvotes: 0

Views: 201

Answers (2)

harre
harre

Reputation: 7287

Use expand.grid {base} :

a <- list()
a[[1]] <- list(c(1:3),c(3:8))
a[[2]] <- list(c(2:6),c(7:9),c(18:24))
a[[3]] <- list(c(11:13),c(10:16),c(17:19),c(11:14),c(17:20))

comb <- expand.grid(a)

Upvotes: 5

A5C1D2H2I1M1N2O1R2T1
A5C1D2H2I1M1N2O1R2T1

Reputation: 193517

As an alternative to expand.grid, if you are looking for more speed as the lists grow, you can check out CJ from the "data.table" package:

The approach would be:

library(data.table)
do.call(CJ, a)

Here are the first few rows:

> head(do.call(CJ, a), 10)
       V1        V2                 V3
 1: 1,2,3 2,3,4,5,6           11,12,13
 2: 1,2,3 2,3,4,5,6 10,11,12,13,14,15,
 3: 1,2,3 2,3,4,5,6           17,18,19
 4: 1,2,3 2,3,4,5,6        11,12,13,14
 5: 1,2,3 2,3,4,5,6        17,18,19,20
 6: 1,2,3     7,8,9           11,12,13
 7: 1,2,3     7,8,9 10,11,12,13,14,15,
 8: 1,2,3     7,8,9           17,18,19
 9: 1,2,3     7,8,9        11,12,13,14
10: 1,2,3     7,8,9        17,18,19,20

(The do.call approach would also work with expand.grid).


Quick comparison:

a <- list()
a[[1]] <- list(c(1:3),c(3:8))
a[[2]] <- list(c(2:6),c(7:9),c(18:24))
a[[3]] <- list(c(11:13),c(10:16),c(17:19),c(11:14),c(17:20))

## 15 item list
a <- unlist(replicate(5, a, FALSE), recursive = FALSE)

system.time(do.call(expand.grid, a))
#    user  system elapsed 
#   8.020   2.232  10.254 
system.time(do.call(CJ, a))
#    user  system elapsed 
#   2.180   0.828   3.004 

Upvotes: 3

Related Questions