user6549804
user6549804

Reputation:

In R, how can I get a combination of every element in a list and then concatenate them?

I have a list, and I am trying to choose a specific number from it. For example:

x <- list()
x[[1]] <- c(1,2,3)
x[[2]] <- c(4,5,6)
x[[3]] <- c(7,8,9)

Now I do this:

y <- combn(x,2)

y looks like this:

      [,1]      [,2]      [,3]     

[1,] Numeric,3 Numeric,3 Numeric,3

[2,] Numeric,3 Numeric,3 Numeric,3

A matrix is returned with columns representing each set. However, I want to concatenate them column-wise, but I cannot do so.

cbind(y)

     [,1]      [,2]      [,3]     

[1,] Numeric,3 Numeric,3 Numeric,3

[2,] Numeric,3 Numeric,3 Numeric,3

There should be only one row, but there are two! In addition, when I concatenate specific elements, this happens:

c(y[1,1],y[2,1])

[[1]]

[1] 1 2 3

[[2]]

[1] 4 5 6

This is just an example. The actual list is much larger. How can I accomplish this? Basically, I'm trying to do k-fold cross validation but each subset of the data is in a list.

Upvotes: 0

Views: 154

Answers (5)

JobHunter69
JobHunter69

Reputation: 2270

Following your example, since your list is not of equal length, you can try this:

for(counter in i : ncol(y)){
    newList[[counter]] <- do.call(c, y[1 : 2, counter]
}

Upvotes: 0

bgoldst
bgoldst

Reputation: 35314

We can take combinations of the list indexes, and for each combination combine the two corresponding list components into a vector.

To preserve the list structure we must pass simplify=F to combn():

combn(seq_along(x),2L,function(i) c(x[[i[1L]]],x[[i[2L]]]),simplify=F);
## [[1]]
## [1] 1 2 3 4 5 6
##
## [[2]]
## [1] 1 2 3 7 8 9
##
## [[3]]
## [1] 4 5 6 7 8 9
##

Actually there's an even easier way to do it:

combn(x,2L,unlist,simplify=F);
## [[1]]
## [1] 1 2 3 4 5 6
##
## [[2]]
## [1] 1 2 3 7 8 9
##
## [[3]]
## [1] 4 5 6 7 8 9
##

Upvotes: 2

akrun
akrun

Reputation: 887108

We can use this within combn itself as it has the FUN argument.

combn(1:3, 2, FUN = function(i) list(do.call(cbind, x[i])))
#[[1]]
#     [,1] [,2]
#[1,]    1    4
#[2,]    2    5
#[3,]    3    6

#[[2]]
#     [,1] [,2]
#[1,]    1    7
#[2,]    2    8
#[3,]    3    9

#[[3]]
#     [,1] [,2]
#[1,]    4    7
#[2,]    5    8
#[3,]    6    9

Upvotes: 1

alistaire
alistaire

Reputation: 43334

You can just make a matrix of indices with combn and apply across it, do.call(cbind, ...)ing each pair. You'll need an extra list() call so apply doesn't simplify everything into one matrix:

apply(combn(1:3, 2), 2, function(i){list(do.call(cbind, x[i]))})
## [[1]]
## [[1]][[1]]
##      [,1] [,2]
## [1,]    1    4
## [2,]    2    5
## [3,]    3    6
## 
## 
## [[2]]
## [[2]][[1]]
##      [,1] [,2]
## [1,]    1    7
## [2,]    2    8
## [3,]    3    9
## 
## 
## [[3]]
## [[3]][[1]]
##      [,1] [,2]
## [1,]    4    7
## [2,]    5    8
## [3,]    6    9

The elements are annoyingly nested, but a purrr::flatten() call neatens the structure easily enough.

Upvotes: 0

SamPassmore
SamPassmore

Reputation: 1365

From your question I think what you want is to make each list a column in a matrix. Please correct your question if this is not the case.

What you want to use is do.call(). I recommend looking at the documentation for this function (?do.call) - but briefly it executes a function on a list.

x <- list()
x[[1]] <- c(1,2,3)
x[[2]] <- c(4,5,6)
x[[3]] <- c(7,8,9)

do.call(cbind, x)
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

Upvotes: 1

Related Questions