Reputation: 23104
I have a list like this:
x = list(a = 1:4, b = 3:10, c = NULL)
x
#$a
#[1] 1 2 3 4
#
#$b
#[1] 3 4 5 6 7 8 9 10
#
#$c
#NULL
and I want to extract all elements that are not null. How can this be done? Thanks.
Upvotes: 46
Views: 26124
Reputation: 465
Using purrr
's compact()
just do
library(purrr)
x = list(a = 1:4, b = 3:10, c = NULL)
compact(x)
#> $a
#> [1] 1 2 3 4
#>
#> $b
#> [1] 3 4 5 6 7 8 9 10
Created on 2024-09-02 with reprex v2.1.1
Upvotes: 1
Reputation: 39647
An option is to use %in%
.
x[!x %in% list(NULL)]
#$a
#[1] 1 2 3 4
#
#$b
#[1] 3 4 5 6 7 8 9 10
Or is.null
in vapply
.
x[!vapply(x, is.null, FALSE)]
Or to use lengths
, but this will fail in case the list contains e.g. numeric(0)
.
x[lengths(x) > 0]
Benchmark
x = list(a = 1:4, b = 3:10, c = NULL)
bench::mark(
sapply = x[!sapply(x,is.null)],
Filter = Filter(Negate(is.null), x),
"in" = x[!x %in% list(NULL)],
lapply = x[!unlist(lapply(x, is.null))],
vapply = x[!vapply(x, is.null, FALSE)],
lengths = x[lengths(x) > 0] )
# expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
# <bch:expr> <bch:t> <bch:t> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
#1 sapply 19.85µs 22.73µs 40853. 0B 12.3 9997 3 244.7ms
#2 Filter 11.84µs 13.73µs 70067. 0B 14.0 9998 2 142.7ms
#3 in 9.87µs 11.45µs 81415. 0B 8.14 9999 1 122.8ms
#4 lapply 6.4µs 7.49µs 126673. 0B 12.7 9999 1 78.9ms
#5 vapply 4.64µs 5.51µs 177842. 0B 17.8 9999 1 56.2ms
#6 lengths 2.12µs 2.32µs 414271. 0B 0 10000 0 24.1ms
Upvotes: 2
Reputation: 1058
x[!sapply(x,is.null)]
This generalizes to any logical statement about the list, just sub in the logic for "is.null".
Upvotes: 15
Reputation: 343
Simpler and likely quicker than the above, the following works for lists of any non-recursive (in the sense of is.recursive
) values:
example_1_LST <- list(NULL, a=1.0, b=Matrix::Matrix(), c=NULL, d=4L)
example_2_LST <- as.list(unlist(example_1_LST, recursive=FALSE))
str(example_2_LST)
prints:
List of 3
$ a: num 1
$ b:Formal class 'lsyMatrix' [package "Matrix"] with 5 slots
.. ..@ x : logi NA
.. ..@ Dim : int [1:2] 1 1
.. ..@ Dimnames:List of 2
.. .. ..$ : NULL
.. .. ..$ : NULL
.. ..@ uplo : chr "U"
.. ..@ factors : list()
$ d: int 4
Upvotes: 1
Reputation: 60452
What about:
x[!unlist(lapply(x, is.null))]
Here is a brief description of what is going on.
lapply
tells us which elements are NULL
R> lapply(x, is.null)
$a
[1] FALSE
$b
[1] FALSE
$c
[1] TRUE
Next we convect the list into a vector:
R> unlist(lapply(x, is.null))
a b c
FALSE FALSE TRUE
Then we switch TRUE
to FALSE
:
R> !unlist(lapply(x, is.null))
a b c
TRUE TRUE FALSE
Finally, we select the elements using the usual notation:
x[!unlist(lapply(x, is.null))]
Upvotes: 14