118
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

My list has 13 elements, 11 of which are NULL. I would like to remove them, but preserve the indices of the elements that are nonempty.

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

[[2]]
[1] 456

This removes the NULL elements just fine, but I don't want the nonempty elements to be reindexed, i.e, I want mylist2 to look something like this, where the indices of the nonempty entries are preserved.

> mylist2
[[11]]
[1] 123

[[13]]
[1] 456
zx8754
  • 52,746
  • 12
  • 114
  • 209
Adrian
  • 9,229
  • 24
  • 74
  • 132
  • 1
    Someone may find a way, but I think you are falling into the "Why is it printing that way" trap. Those index numbers are not the names of your list elements. There are no names. Check `names(mylist)`. So they are just helpers showing where in the list the elements are. That's why you're having trouble telling R to return the 11th position of a list with only two elements. You can try naming the the list as the answer below. – Pierre L Oct 07 '15 at 23:49
  • 5
    IMO this answer should be updated to @Hayward-Oblad's purrr solution below. Either `list %>% discard(is.null)` or `list %>% discard(~ length(.x) == 0)`. – geotheory Dec 06 '19 at 13:43

8 Answers8

130

The closest you'll be able to get is to first name the list elements and then remove the NULLs.

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
Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
  • 22
    or `x <- x[!sapply(x,is.null)]` – xm1 Jul 11 '20 at 00:19
  • 2
    @xm1's answer is better since the right hand side expression returns the list without the `NULL`s hence can be written into a convenience function like this `remove_null_lst <- function(x) x[!sapply(x, is.null)]` – Prashant Bharadwaj Apr 01 '21 at 22:01
65

Simply use mylist[lengths(mylist) != 0].

Function lengths() was introduced in R 3.2.0 (April 2015).

F. Privé
  • 11,423
  • 2
  • 27
  • 78
  • 1
    Users stuck with even older R versions can use `vapply(mylist, length, 1L)`, it's ever-so-slightly vaster (and maybe harder to read to the untrained eye) – MichaelChirico Jul 27 '19 at 11:31
53

The purrr package, included in Tidyverse, has elegant and fast functions for working with lists:

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(.) )

All above options are from Purrr. Output is:

[[1]] 
[1] 123

[[2]] 
[1] 456

Note: compact() was in plyr, but dplyr superseded plyr, and compact() stayed around but moved to purrr. Anyway, all the functions are within the parent package tidyverse.



Here's a link to the Purrr cheat sheet download:

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

Or to view the Purrr cheatsheet directly in a browser:

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

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
Hayward Oblad
  • 709
  • 5
  • 6
30

There's a function that automatically removes all the null entries of a list, and if the list is named, it maintains the names of the non-null entries.

This function is called compact from the package plyr.

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

plyr::compact(l)

If you want to preserve the indexes of the non-null entries, you can name the list as it is done in the post before and then compact your list:

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

If you want to keep the names you can do

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

You can then access the elements like so

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

You can't get them in the neat [[11]], [[13]] notation, though, because those represent numerical indices.

Felipe Gerard
  • 1,552
  • 13
  • 23
6

This solution works with nested list as well

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

Here it is with convenient chaining notation

library(magrittr)

mylist %>%
  setNames(seq_along(.)) %>%
  Filter(. %>% is.null %>% `!`, .)
bramtayl
  • 4,004
  • 2
  • 11
  • 18
4

here's a very simple way to do it using only base R functions:

names(mylist) <- 1:length(mylist)
mylist2 <- mylist[which(!sapply(mylist, is.null))]
itsmisterbrown
  • 471
  • 4
  • 3