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

R: удаление элементов NULL из списка

mylist <- list(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
    123, NULL, 456)

> mylist
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]
NULL

[[5]]
NULL

[[6]]
NULL

[[7]]
NULL

[[8]]
NULL

[[9]]
NULL

[[10]]
NULL

[[11]]
[1] 123

[[12]]
NULL

[[13]]
[1] 456

В моем списке 13 элементов, 11 из которых имеют NULL. Я хотел бы удалить их, но сохранить индексы непустых элементов.

mylist2 = mylist[-which(sapply(mylist, is.null))]
> mylist2
[[1]]
[1] 123

[[2]]
[1] 456

Это удаляет элементы NULL просто отлично, но я не хочу, чтобы непустые элементы были переиндексированы, т.е. я хочу, чтобы mylist2 выглядел примерно так, где индексы непустых записей сохраняются.

> mylist2
[[11]]
[1] 123

[[13]]
[1] 456
4b9b3361

Ответ 1

Ближе всего вы сможете получить, чтобы сначала назвать элементы списка, а затем удалить NULL.

names(x) <- seq_along(x)

## Using some higher-order convenience functions
Filter(Negate(is.null), x)
# $`11`
# [1] 123
# 
# $`13`
# [1] 456

# Or, using a slightly more standard R idiom
x[sapply(x, is.null)] <- NULL
x
# $`11`
# [1] 123
# 
# $`13`
# [1] 456

Ответ 2

Здесь есть функция, которая автоматически удаляет все нулевые записи в списке, а если список указан, он поддерживает имена ненулевых записей.

Эта функция называется compact из пакета plyr.

l <- list( NULL, NULL, foo, bar)
names(l) <- c( "one", "two", "three", "four" )

plyr::compact(l)

Если вы хотите сохранить индексы ненулевых записей, вы можете назвать список, как это делается в сообщении перед, а затем скомпилировать список:

names(l) <- seq_along(l)
plyr::compact(l)

Ответ 3

Просто сделайте mylist[lengths(mylist) != 0].

Ответ 4

Если вы хотите сохранить имена, которые вы можете сделать

a <- list(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
          123, NULL, 456)
non_null_names <- which(!sapply(a, is.null))
a <- a[non_null_names]
names(a) <- non_null_names
a

Затем вы можете получить доступ к таким элементам

a[['11']]
num <- 11
a[[as.character(num)]]
a[[as.character(11)]]
a$`11`

Вы не можете получить их в аккуратной нотации [[11]], [[13]], хотя, поскольку они представляют числовые индексы.

Ответ 5

Здесь это с удобной цепной нотации

library(magrittr)

mylist %>%
  setNames(seq_along(.)) %>%
  Filter(. %>% is.null %>% `!`, .)

Ответ 6

Вот очень простой способ сделать это, используя только базовые функции R:

names(mylist) <- 1:length(mylist)
mylist2 <- mylist[which(!sapply(mylist, is.null))]

Ответ 7

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

rlist::list.clean(myNestedlist ,recursive = T)

Ответ 8

purrr пакет, включенный в Tidyverse, имеет элегантные и быстрые функции для работы со списками:

require(tidyverse)

# this works
compact(mylist)

# or this
mylist %>% discard(is.null)

# or this
# pipe "my_list" data object into function "keep()", make lambda function inside "keep()" to return TRUE FALSE.
mylist %>% keep( ~ !is.null(.) )

Все вышеперечисленные варианты от Purrr. Вывод:

[[1]] 
[1] 123

[[2]] 
[1] 456

Примечание: compact() был в plyr, но dplyr заменил plyr, а compact() остался, но перешел на purrr. В любом случае, все функции находятся в родительском пакете tidyverse.



Вот ссылка на скачивание шпаргалки Purrr:

https://rstudio.com/resources/cheatsheets/

Или для просмотра таблицы Purrr прямо в браузере:

https://evoldyn.gitlab.io/evomics-2018/ref-sheets/R_purrr.pdf