Reputation: 1888
I come across lists that I would like to parse before coercing into a data frame. Sometimes I have lists that have elements I'm not expecting. I'd like to be able to remove all of these unexpected elements by name when they arise. Here is an example of a list with an element wackything
that I would like removed without having to call the element index or using a for loop through each sub-element.
my_list <- list(person = list(name = "mike", phone = "111-1111"),
person = list(name = "lisa", phone = "222-2222", wackything = "PLEASE REMOVE ME"),
person = list(name = "kimo", phone = "333-3333"))
I would like my final list to look like this:
final_list <- list(person = list(name = "mike", phone = "111-1111"),
person = list(name = "lisa", phone = "222-2222"),
person = list(name = "kimo", phone = "333-3333"))
so that I can corece it to a data frame using
do.call(rbind, lapply(final_list, rbind))
Upvotes: 6
Views: 1138
Reputation: 4970
You could try this. The first step is similar to 42-'s answer. We then use sapply
, which returns a matrix that we then have to transpose.
my_list <- lapply(my_list, function(x)x[names(x)!= "wackything"])
data.frame(t(sapply(my_list,c)), row.names=NULL)
# name phone
#1 mike 111-1111
#2 lisa 222-2222
#3 kimo 333-3333
Another option that gives you the same result.
data.frame(Reduce(rbind, my_list), row.names=NULL)
We use row.names=NULL
when building the dataframe. You can do it without but that will result in a warning message related to the duplicate rownames that we have.
Upvotes: 2
Reputation: 263331
I think you have too many rbinds in your anticipated use. See if this is satisfactory:
> rmwac <- function(x) x[ !names(x) %in% "wackything"]
> do.call(rbind, lapply(my_list, rmwac))
name phone
person "mike" "111-1111"
person "lisa" "222-2222"
person "kimo" "333-3333"
Notice that epi10's perfectly fine answer use a negative sign and that was possible because grep
returns numeric values and indexing of lists with numeric values is possible. It is not, however, possible to use the negative sign with character and logical values.
Upvotes: 6
Reputation: 93761
bind_rows
from the dplyr
package will work even if not all the lists share the same element names. Then you can remove the columns you don't need.
library(dplyr)
df = bind_rows(my_list)
name phone wackything 1 mike 111-1111 NA 2 lisa 222-2222 PLEASE REMOVE ME 3 kimo 333-3333 NA
df = df[ , -grep("wackything", names(df))]
name phone 1 mike 111-1111 2 lisa 222-2222 3 kimo 333-3333
Upvotes: 5