Remove NULL elements from list of lists

随声附和 提交于 2019-12-17 06:12:58

问题


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"))

回答1:


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"



回答2:


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"



回答3:


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"



回答4:


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"



回答5:


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"



回答6:


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)



回答7:


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)
  }
}


来源:https://stackoverflow.com/questions/26539441/remove-null-elements-from-list-of-lists

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!