Tau
Tau

Reputation: 183

rbinding with a list containing empty lists for NAs in R

I have a nested list with some elements as empty list (extract):

 str(myList)
 List of 100
 $ :'data.frame':   2 obs. of  10 variables:
  ..$ _index          : chr [1:2] "alias_fr" "alias_fr"
  ..$ _type           : chr [1:2] "triplet" "triplet"
  ..$ _id             : chr [1:2] "Q9327" "Q3122270"
 $ : list()
 $ :'data.frame':   1 obs. of  9 variables:
  ..$ _index          : chr "alias_fr"
  ..$ _type           : chr "triplet"
  ..$ _id             : chr "Q17009"

I need to index each element, using bind_rows:

df <- bind_rows(myList, .id = "id")

Unfortunately, the empty elements (second one in the example) are deleted, the consequences being a bad indexing (shift of indexes):

  id   _index   _type      _id
1  1 alias_fr triplet    Q9327
2  1 alias_fr triplet Q3122270
3  2 alias_fr triplet   Q17009

What I expect:

  id   _index   _type      _id
1  1 alias_fr triplet    Q9327
2  1 alias_fr triplet Q3122270
3  2 NA       NA      NA
3  3 alias_fr triplet   Q17009

I have already tried several methods without any success:

Function to change Null to NA

Convert R list to dataframe with missing/NULL elements ...

Is there a way to make the empty elements taken into account with bind_rows?

Upvotes: 0

Views: 1677

Answers (1)

ytu
ytu

Reputation: 1850

Assuming that

  1. All the data frames in your list share the same variable names and number of columns.
  2. Your first element in that nested list is not an empty list. (This is just for my convenience later, you can pick any one element which is a data frame as you like.)

My approach is changing the elements which are not a data frame into one with 1 row of NAs and the same column names with other data frames.

change_others_to_dataframe <- function(x) {
  # If x is a data frame, do nothing and return x
  # Otherwise, return a data frame with 1 row of NAs
  if (is.data.frame(x)) {return(x)}
  else {return(setNames(data.frame(matrix(ncol = ncol(myList[[1]]), nrow = 1)),
                        names(myList[[1]])))}
}

# Apply the written function above to every element in myList
mynewList <- lapply(myList, change_others_to_dataframe)
# "bind_rows" with mynewList
df <- bind_rows(mynewList, .id = "id")

I believe that this would solve your problem.

For creating data frames with no data, you may refer to these threads on SO:

Upvotes: 2

Related Questions