manipulate - Eliminar elementos NULL de la lista de listas
modify list r (7)
¿Cómo elimino los elementos nulos de una lista de listas, como a continuación, en R?
lll <- list(list(NULL),list(1),list("a"))
El objeto que quiero se vería así:
lll <- list(list(1),list("a"))
Vi una respuesta similar aquí: ¿cómo puedo eliminar un elemento de una lista? pero no fue capaz de extenderlo de listas simples a una lista de listas.
EDITAR
Mal ejemplo anterior por mi parte. Ambas respuestas funcionan en casos más simples (arriba). ¿Qué pasa si la lista es como:
lll <- list(list(NULL),list(1,2,3),list("a","b","c"))
Cómo llegar:
lll <- list(list(1,2,3),list("a","b","c"))
Aquí hay una opción usando la combinación de Filter
y Negate
Filter(Negate(function(x) is.null(unlist(x))), lll)
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"
Como tiene listas en listas, probablemente necesite ejecutar l/sapply
dos veces, como por ejemplo:
lll[!sapply(lll,sapply,is.null)]
#[[1]]
#[[1]][[1]]
#[1] 1
#
#
#[[2]]
#[[2]][[1]]
#[1] "a"
Esta solución recursiva tiene la virtud de trabajar en listas aún más profundamente anidadas.
Está muy inspirado en la respuesta de Gabor Grothendieck a esta pregunta bastante similar . Mi modificación de ese código es necesaria si la función también es eliminar objetos como list(NULL)
(no es lo mismo que NULL
), como lo desea.
## 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"
Aquí hay un ejemplo de su aplicación a una lista anidada más profundamente, sobre la cual las otras soluciones actualmente propuestas fallan varias veces.
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"
Hay una nueva lista de paquetes en CRAN, gracias a Kun Ren por hacer nuestra vida más fácil.
list.clean(.data, fun = is.null, recursive = FALSE)
o para la eliminación recursiva de NULL:
list.clean(.data, fun = is.null, recursive = TRUE)
Para este ejemplo en particular, también puede usar unlist
con su argumento recursive
.
lll[!sapply(unlist(lll, recursive=FALSE), is.null)]
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"
Solución rápida a la solución de Josh O''Brien. Hay un poco de un problema con las listas de funciones
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)
}
}
Usando 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"