EN VI

R - unlist nested lists without losing Nulls?

2024-03-11 20:00:06
How to R - unlist nested lists without losing Nulls
  dat=list(list(id = "T"), list(id = "T"), 
structure(list(NULL), names = NA_character_), list(id = "T"), 
list(id = "T"), list(id = "T"))

      unlist(dat)

I treid but did not work

    dat[sapply(dat, is.null)] <- NA

Solution:

You should use the answer by ThomasIsCoding with a list as above, where you do not want to recursively unlist.

However, if it is possible you will have NULL at the top level, or if you want to unlist every level, then you need to traverse the levels of the list, setting NULL to NA.

tidyverse approach

I like to use purrr::modify_tree() for operations like this, passing a function to apply to every leaf.

dat |> 
    purrr::modify_tree(
        leaf = \(x) if(is.null(x)) NA else x,
        post = unlist
    )
#   id   id <NA>   id   id   id 
#  "T"  "T"   NA  "T"  "T"  "T" 

The post parameter is a function that is applied on the way "up", i.e. after the leaves are transformed.

base R approach

It feels as if you ought to be able to use base::rapply() to recursively iterate. Unfortunately, it ignores NULL elements. We can write a recursive function:

replace_null  <- function(x, repl = NA) {
    if(is.list(x)) return(lapply(x, replace_null))
    if(is.null(x)) repl else x # or in R 4.4:   x %||% repl
}
unlist(replace_null(dat))
#   id   id <NA>   id   id   id 
#  "T"  "T"   NA  "T"  "T"  "T" 

The null coalescing operator %||%

Incidentally if you're using the current development version of R (to be released as 4.4) you can use the null coalescing operator.

L %||% R newly in base is an expressive idiom for the phrases if(!is.null(L)) L else R or if(is.null(L)) R else L.

Here is an example of the difference of this approach when one of the top-level items is NULL.

l  <- list(1, NULL)
unlist(l)
# [1] 1

dat |> 
    purrr::modify_tree(
        leaf = \(x) x %||% NA,
        post = unlist
    )
# [1]  1 NA
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login