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
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
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
approachI 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.
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"
%||%
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 phrasesif(!is.null(L)) L else R
orif(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