0

I have a list with lists like this:

# output from a package function
A <- list(a = matrix(1:9,ncol=3),
          b = matrix(1:8,ncol=4),
          c = 1.5)

B <- list(a = matrix(11:19,ncol=3),
          b = matrix(11:18,ncol=4),
          c = 2.5)

# list with all outputs (from loaded=lapply(filenames, function(x) get(load(x))) )
superlist <- list(A, B))

What I would like to do is first add the name of each list item (A, B) to all second order list elements. For example B would become:

B <- list(a = cbind(matrix(11:19,ncol=3),c("B","B","B")),
           b = cbind(matrix(11:18,ncol=4),c("B","B")),
           c = c(2.5,"B"))

Then, the aim is to rbind all matrices, values or dataframes (a,b,c) with the same name together, so that I would have:

superlist <- list(a = rbind(cbind(matrix(1:9,ncol=3),c("A","A","A")),cbind(matrix(11:19,ncol=3),c("B","B","B"))),
           b = rbind(cbind(matrix(1:8,ncol=4),c("A","A")),cbind(matrix(11:18,ncol=4),c("B","B"))),
           c = rbind(c(1.5,"A"),c(2.5,"B")))

For the rbinding, the best I got is this (from rbind all dataframes in a list of lists by name):

do.call("rbind",lapply(superlist ,function(x) x[["a"]]))

However, it only does it for one list element (and I have more than 20). I know that I can write a loop, but as I will be using the function often I would like to know how to do this nicer.

I am aware that there are multiple questions asked about this, but none of them has exactly the same problem (for example, some only have data frames as list of list elements, sometimes all of the same size). So although certain questions provided a bit of help, none truly gave me enough information to resolve my problem.

Thank you

Community
  • 1
  • 1
Wave
  • 1,216
  • 1
  • 9
  • 22
  • "What I would like to do is first add the name of each list item (A, B) to all second order list elements." -- Don't do this. You're contaminating the numbers in your data with characters from the names, e.g., in `cbind(matrix(11:19,ncol=3),c("B","B","B"))` – Frank Aug 02 '16 at 15:23

1 Answers1

1

I think can utilize the function proposed in this answer. It reverses the list structure i.e. groups by inner list. An example:

# output from a package function
A <- list(a = matrix(1:9,ncol=3),
      b = matrix(1:8,ncol=4),
      c = 1.5)

B <- list(a = matrix(11:19,ncol=3),
      b = matrix(11:18,ncol=4),
      c = 2.5)

# list with all outputs (from loaded=lapply(filenames, function(x)      get(load(x))) )
superlist <- list(A, B)
################### your code above ##############
## the function from the linked answer
fun <-  function(ll) {
    nms <- unique(unlist(lapply(ll, function(X) names(X))))
    ll <- lapply(ll, function(X) setNames(X[nms], nms))
    ll <- apply(do.call(rbind, ll), 2, as.list)
    lapply(ll, function(X) X[!sapply(X, is.null)])
}

## apply the function to your list
insideout <- fun(superlist)

## rbind the components together
lapply(insideout, function(x) do.call(rbind, x))

Is this what you intended to do?

Community
  • 1
  • 1
AEF
  • 5,408
  • 1
  • 16
  • 30
  • Yes, this works great! However, do you also know how to add a column with names (the first part of my question)? As Frank says, it "contaminates my matrix, but I don't care about that (for later on, labeling is more important than "contamination"). – Wave Aug 02 '16 at 15:34
  • Well, there cannot be a way to do this automatically as the names "A" and "B" are chosen by you and are not related to your data (at least in your example). Also I agree with Frank. Converting your whole matrix to character to have labels is really bad. Instead consider using a data.frame and add a column for the names or to use rownames for the matrix. – AEF Aug 02 '16 at 16:52