NULL represents a null object, and sometimes, it’s logical for the project to filter it out from either a list or data frame.
Here are three ways to remove NULL values from a list in R:
- Using Filter() with Negate() and is.null()
- Using sapply() or lapply() with Subsetting
- Using purrr::discard() (Tidyverse Approach)
For example, if you have a list that contains the following values:
main_list = list(11, NULL, "KRUNAL", NULL, 1.9)
In the above main_list, there are two NULL values at positions 2 and 4.
Method 1: Using Filter() with Negate() and is.null()
For checking NULL values in the list, we can use the is.null() function that returns boolean TRUE for NULL value and FALSE otherwise. On top of that, we will use Negate() and Filter() functions to check each element, retain non-NULL values, and remove all the NULL values.
Syntax
filtered_list <- Filter(Negate(is.null), main_list)
Code
main_list <- list(11, NULL, "KRUNAL", NULL, 1.9)
print(main_list)
filtered_list <- Filter(Negate(is.null), main_list)
print(filtered_list)
Output
The Filter() approach helps remove top-level NULL values. However, NULL is not the same as NA or NaN. If you want to find NA values, use the is.na() function.
Pros
- It is efficient and faster for larger lists.
- It clearly expresses the intent of filtering.
- We don’t need external packages.
Cons
-
If you have nested lists that contain NULL, you must use a different approach, as this approach won’t remove NULL from a nested list.
Method 2: Using sapply() with Subsetting
The sapply() is a base R function that is helpful when applying a specific function to the whole list. If I use is.null() function with sapply(), I would get a list of logical values suggesting which elements are NULL.
Then, I can subset the original list where NULL values are removed using the negation operator (!).
Syntax
main_list[!sapply(main_list, is.null)]
Code
main_list <- list(11, NULL, "KRUNAL", NULL, 1.9)
print(main_list)
without_null_list <- main_list[!sapply(main_list, is.null)]
print(without_null_list)
Output
Pros
- No external packages are required.
Cons
- It requires explicit subsetting and negation, which is slightly slower for very large lists compared to the Filter() approach.
Method 3: Using purrr::discard()
The purrr is a third-party package that provides a discard() function to remove NULL elements that satisfy the is.null predicate.
Install and load the purrr library like this:
library(purrr)
Syntax
filtered_list <- discard(main_list, is.null)
Code
library(purrr)
main_list <- list(11, NULL, "KRUNAL", NULL, 1.9)
print(main_list)
filtered_list <- discard(main_list, is.null)
print(filtered_list)
Output
Pros
- It can handle complex predicates.
- It works seamlessly with a tidyverse ecosystem.
Cons
- It requires installing and loading purrr.
- It is slightly slower for small lists than base R methods (but negligible in most cases).
Removing NULL values from nested lists
We can write a recursive function to traverse the list and remove NULL values at all levels. It requires a recursive approach because NULL values can exist at any level of the list hierarchy.
remove_nulls_recursive <- function(x) {
# Base case: if x is not a list, return it as is
if (!is.list(x)) {
return(x)
}
# Recursively apply the function to each element
x <- lapply(x, remove_nulls_recursive)
# Remove NULL elements at the current level
x <- x[!sapply(x, is.null)]
return(x)
}
nested_list <- list(
a = 1,
b = NULL,
c = list(
d = NULL,
e = 2,
f = list(
g = NULL,
h = 3
)
)
)
print("Before removing NULLs:")
print(nested_list)
# Remove NULLs
cleaned_list <- remove_nulls_recursive(nested_list)
print("After removing NULLs:")
print(cleaned_list)
Output
[1] "Before removing NULLs:"
$a
[1] 1
$b
NULL
$c
$c$d
NULL
$c$e
[1] 2
$c$f
$c$f$g
NULL
$c$f$h
[1] 3
[1] "After removing NULLs:"
$a
[1] 1
$c
$c$e
[1] 2
$c$f
$c$f$h
[1] 3
That’s all!
Krunal Lathiya is a seasoned Computer Science expert with over eight years in the tech industry. He boasts deep knowledge in Data Science and Machine Learning. Versed in Python, JavaScript, PHP, R, and Golang. Skilled in frameworks like Angular and React and platforms such as Node.js. His expertise spans both front-end and back-end development. His proficiency in the Python language stands as a testament to his versatility and commitment to the craft.