R: Removing Null Elements from a List

R: removing NULL elements from a list

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

Recursive remove NULL elements of list of lists

One approach is to use rrapply in the rrapply-package (extension of base rapply):

library(rrapply)

x <- list(a=1, b=2, c=list(ca=1, cb=2, cc=NULL), d=NULL)

rrapply(x, condition = Negate(is.null), how = "prune")
#> $a
#> [1] 1
#>
#> $b
#> [1] 2
#>
#> $c
#> $c$ca
#> [1] 1
#>
#> $c$cb
#> [1] 2

Benchmark timings

Benchmarking the computation time of rrapply against rlist's list.clean function for some large nested lists, I get the following results:

## recursively create nested list with dmax layers and 50% NULL elements
f <- function(len, d, dmax) {
x <- vector(mode = "list", length = len)
for(i in seq_along(x)) {
if(d + 1 < dmax) {
x[[i]] <- Recall(len, d + 1, dmax)
} else {
x[[i]] <- list(1, NULL)
}
}
return(x)
}

## long shallow list (3 layers, total 5e5 nodes)
x_long <- f(len = 500, d = 1, dmax = 3)

microbenchmark::microbenchmark(
rlist = rlist::list.clean(x_long, recursive = TRUE),
rrapply = rrapply::rrapply(x_long, condition = Negate(is.null), how = "prune"),
check = "equal",
times = 5L
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval
#> rlist 2331.4914 2343.3001 2438.9674 2441.3850 2512.3484 2566.3121 5
#> rrapply 353.7169 393.0646 400.8198 399.7971 417.7235 439.7972 5

## deeply nested list (18 layers, total 2^18 nodes)
x_deep <- f(len = 2, d = 1, dmax = 18)

microbenchmark::microbenchmark(
rlist = rlist::list.clean(x_deep, recursive = TRUE),
rrapply = rrapply::rrapply(x_deep, condition = Negate(is.null), how = "prune"),
check = "equal",
times = 5L
)
#> Unit: milliseconds
#> expr min lq mean median uq max neval
#> rlist 2167.2946 2251.5203 2279.9963 2292.5045 2332.4432 2356.2188 5
#> rrapply 268.9463 274.7437 325.9585 292.4559 354.1607 439.4857 5

Extract non null elements from a list in R

Here's another option:

Filter(Negate(is.null), x)

Extract non null elements from a list in R

Here's another option:

Filter(Negate(is.null), x)

Remove null list-columns

We could use select_if. NULL doesn't exist within a vector. So, the condition should be to check if the column is a list and if all the elements are NULL (is.null), negate (!) to select all the other columns

library(dplyr)
library(purrr)
null_list %>%
select_if(~ !(is.list(.) && all(map_lgl(., is.null))))
# A tibble: 3 x 1
# name
# <int>
#1 1
#2 2
#3 3

NOTE: This check if all the values in the list are NULL and then it removes those columns


If it is deeply nested,

example %>%     
select(where(~ !(is.list(.) && is.null(unlist(.)))))
# A tibble: 3 x 3
# a b c
# <dbl> <dbl> <list>
#1 1 4 <NULL>
#2 2 5 <NULL>
#3 3 6 <list [3]>

Or to select only the list column with any non-NULL elements

example %>%     
select(where(~ is.list(.) && !is.null(unlist(.))))
# A tibble: 3 x 1
# c
# <list>
#1 <NULL>
#2 <NULL>
#3 <list [3]>

data

 example <- tibble(a = c(1, 2, 3), b = c(4, 5, 6),
c = list(NULL, NULL, list(1,2,3)),
d = list(NULL, NULL, list(x = NULL, y = NULL, z = NULL)))

How to Remove Null Values in a List

This would be much easier if you just used Filter() and Map() For example

df.numeric.summary <- function(data.frame1){
my_summary <- function(x) c(
"Mean"=mean(x, na.rm = TRUE),
"Median"=median(x, na.rm=TRUE),
"IQR"=IQR(x, na.rm=TRUE))

Map(my_summary, Filter(is.numeric, data.frame1))
}

You can test with

df.numeric.summary(iris)


Related Topics



Leave a reply



Submit