Подтвердить что ты не робот

Удалить элементы NULL из списка списков

Как удалить нулевые элементы из списка списков, как показано ниже, в R:

lll <- list(list(NULL),list(1),list("a"))

Объект, который я хочу, будет выглядеть так:

lll <- list(list(1),list("a"))

Я увидел аналогичный ответ здесь: Как удалить элемент из списка?, но не смог расширить его от простых списков до списка списков.

ИЗМЕНИТЬ

Плохой пример выше с моей стороны. Оба ответа работают в более простом случае (см. Выше). Что, если список похож:

lll <- list(list(NULL),list(1,2,3),list("a","b","c"))

Как получить:

lll <- list(list(1,2,3),list("a","b","c"))
4b9b3361

Ответ 1

Это рекурсивное решение имеет преимущество в работе с еще более глубоко вложенными списками.

Он очень похож на Gabor Grothendieck на этот довольно похожий вопрос. Мое изменение этого кода необходимо, если функция также удаляет объекты, такие как list(NULL) (не то же самое, что и NULL), как вы этого хотите.

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

Вот пример его приложения для более глубоко вложенного списка, по которому другие предлагаемые в настоящее время решения по-разному терпят неудачу.

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

Здесь опция с использованием комбинаций Filter и Negate

Filter(Negate(function(x) is.null(unlist(x))), lll)
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"

Ответ 3

В этом конкретном примере вы также можете использовать unlist с аргументом recursive.

lll[!sapply(unlist(lll, recursive=FALSE), is.null)]
# [[1]]
# [[1]][[1]]
# [1] 1
#
#
# [[2]]
# [[2]][[1]]
# [1] "a"

Ответ 4

Используя 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

Поскольку у вас есть списки в списках, вам, вероятно, нужно дважды запустить l/sapply, например:

lll[!sapply(lll,sapply,is.null)]

#[[1]]
#[[1]][[1]]
#[1] 1
#
#
#[[2]]
#[[2]][[1]]
#[1] "a"

Ответ 6

На CRAN появился новый пакет rlist, спасибо Kun Ren за то, что он сделал нашу жизнь проще.

    list.clean(.data, fun = is.null, recursive = FALSE)

или для рекурсивного удаления NULL:

    list.clean(.data, fun = is.null, recursive = TRUE)

Ответ 7

Быстрое исправление решения Josh O'Brien. Там немного проблема со списками функций

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