How do I remove the null elements from a list of lists, like below, in R:
lll <- list(list(NULL),list(1),list("a"))
The object I want would look like:
lll <- list(list(1),list("a"))
I saw a similar answer here: How can I remove an element from a list? but was not able to extend it from simple lists to a list of lists.
EDIT
Bad example above on my part. Both answers work on simpler case (above). What if list is like:
lll <- list(list(NULL),list(1,2,3),list("a","b","c"))
How to get:
lll <- list(list(1,2,3),list("a","b","c"))
This recursive solution has the virtue of working on even more deeply nested lists.
It's closely modeled on Gabor Grothendieck's answer to this quite similar question . My modification of that code is needed if the function is to also remove objects like list(NULL)
(not the same as NULL
), as you are wanting.
## A helper function that tests whether an object is either NULL _or_
## a list of NULLs
is.NullOb <- function(x) is.null(x) | all(sapply(x, is.null))
## Recursively step down into list, removing all such objects
rmNullObs <- function(x) {
x <- Filter(Negate(is.NullOb), x)
lapply(x, function(x) if (is.list(x)) rmNullObs(x) else x)
}
rmNullObs(lll)
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"
Here is an example of its application to a more deeply nested list, on which the other currently proposed solutions variously fail.
LLLL <- list(lll)
rmNullObs(LLLL)
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [[1]][[1]][[1]][[1]]
# [1] 1
#
#
# [[1]][[1]][[2]]
# [[1]][[1]][[2]][[1]]
# [1] "a"
Here's an option using Filter
and Negate
combination
Filter(Negate(function(x) is.null(unlist(x))), lll)
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"
Using purrr
purrr::map(lll, ~ purrr::compact(.)) %>% purrr::keep(~length(.) != 0)
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 2
[[1]][[3]]
[1] 3
[[2]]
[[2]][[1]]
[1] "a"
[[2]][[2]]
[1] "b"
[[2]][[3]]
[1] "c"
For this particular example you can also use unlist
with its recursive
argument.
lll[!sapply(unlist(lll, recursive=FALSE), is.null)]
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"
Since you have lists in lists, you probably need to run l/sapply
twice, like:
lll[!sapply(lll,sapply,is.null)]
#[[1]]
#[[1]][[1]]
#[1] 1
#
#
#[[2]]
#[[2]][[1]]
#[1] "a"
There is a new package rlist on CRAN, thanks to Kun Ren for making our life easier.
list.clean(.data, fun = is.null, recursive = FALSE)
or for recursive removal of NULL:
list.clean(.data, fun = is.null, recursive = TRUE)
Quick fix on Josh O'Brien's solution. There's a bit of an issue with lists of functions
is.NullOb <- function(x) if(!(is.function(x))) is.null(x) | all(sapply(x, is.null)) else FALSE
## Recursively step down into list, removing all such objects
rmNullObs <- function(x) {
if(!(is.function(x))) {
x = x[!(sapply(x, is.NullOb))]
lapply(x, function(x) if (is.list(x)) rmNullObs(x) else x)
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.