21

Given a list:

alist = list(
  list(name="Foo",age=22),
  list(name="Bar"),
  list(name="Baz",age=NULL)
 )

what's the best way to convert this into a dataframe with name and age columns, with missing values (I'll accept NA or "" in that order of preference)?

Simple methods using ldply fail because it tries to convert each list element into a data frame, but the one with the NULL barfs because the lengths don't match. Best I have at the moment is:

> ldply(alist,function(s){t(data.frame(unlist(s)))})
  name  age
1  Foo   22
2  Bar <NA>
3  Baz <NA>

but that's pretty icky and the numeric variable becomes a factor...

1
  • Kind of annoying that check.rows=FALSE still gives an error about rows having different numbers of observations... Commented Apr 3, 2013 at 17:26

2 Answers 2

18

Step1: remove NULL items

non.null.list <- lapply(alist, Filter, f = Negate(is.null))

Step2: stack everything together:

library(plyr)
rbind.fill(lapply(non.null.list, as.data.frame))
#   name age
# 1  Foo  22
# 2  Bar  NA
# 3  Baz  NA

Edit: In case you had a variable that is NULL for all your list items, it would not show up in your final output. If instead, you'd like a column filled with NA, the first step should not remove NULLs but replace them with NAs:

Step 1 alternative: replace NULL with NA:

non.null.list <- lapply(alist, lapply, function(x)ifelse(is.null(x), NA, x))
Sign up to request clarification or add additional context in comments.

2 Comments

That second step was the subject of this question: stackoverflow.com/questions/15753091/…, for which Josh O'Brien had a longer but more scalable answer.
I'm holding out for a solution that only has one loop/apply step... Otherwise this seems to crack it.
11

A comment mentioned wanting only a single loop, which can be achieved with @flodel's answer just by putting the body of the two loops together:

rbind.fill(lapply(alist, function(f) {
  as.data.frame(Filter(Negate(is.null), f))
}))

giving

  name age
1  Foo  22
2  Bar  NA
3  Baz  NA

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.