Daniel Krizian
Daniel Krizian

Reputation: 4716

rlist: recursively filter out list nodes with NA

Using (preferably) rlist package, is there a way to filter out nodes of the (multi-level) list, so that the resulting list holds no NA values on any level?

library(rlist)
devs <- 
  list(
    p1=list(name="Ken",age=24,
      interest=c("reading","music","movies"),
      lang=list(r=NA,csharp=4)),                      # <------ NA here
    p2=list(name="James",age=25,
      interest=c("sports","music"),
      lang=list(r=3,java=2,cpp=5)),
    p3=list(name="Penny",age=NA,                      # <------ NA here
      interest=c("movies","reading"),
      lang=list(r=1,cpp=4,python=2)))

In the above example, since p1 and p3 nodes contain NA somewhere in their hierarchy, the expected output list should be p2 only. We don't know in advance the structure or names of the input list.

Upvotes: 6

Views: 512

Answers (2)

arvi1000
arvi1000

Reputation: 9582

How about:

# for every element in devs, does it have 0 NA elements when unlisted?
sapply(devs, function(x) !anyNA(unlist(x)))

which returns:

p1    p2   p3 
FALSE TRUE FALSE 

You can get just the desired list element(s) with:

devs[sapply(devs, function(x) !anyNA(unlist(x)))]

Upvotes: 6

Kun Ren
Kun Ren

Reputation: 4993

list.search() scans the list recursively on a condition and can be used to find NAs in child elements of devs.

Using pipeR and rlist together to make the code clearer:

devs %>>% 
  list.filter(. %>>% 
      list.search(anyNA(.)) %>>% 
      length == 0L)

This singles out p2 only.

This is almost a direct translation of your request :)

or an easier way is

list.filter(devs, !anyNA(unlist(.)))

Upvotes: 3

Related Questions