CGP
CGP

Reputation: 169

Remove null list-columns

I have a data frame with null list columns, similar to this:

null_list <- list(NULL, NULL, NULL) %>% enframe()
null_list
#   name value 
#  <int> <list>
#1     1 <NULL>
#2     2 <NULL>
#3     3 <NULL>

I'd like to remove all columns that only contain NULL values like the "value" column above, because when I try to unnest_wider these columns (as part of a loop), I receive the error "replacement has length zero."

Upvotes: 2

Views: 546

Answers (3)

akrun
akrun

Reputation: 887531

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

Upvotes: 2

daniellga
daniellga

Reputation: 1224

Like this?

library(tibble)

null_list <- list(NULL, NULL, NULL) %>% enframe()

> null_list
# A tibble: 3 x 2
   name value 
  <int> <list>
1     1 <NULL>
2     2 <NULL>
3     3 <NULL>


null_list <- rbind(null_list, c(3, "a"))

> null_list
# A tibble: 4 x 2
  name  value    
  <chr> <list>   
1 1     <NULL>   
2 2     <NULL>   
3 3     <NULL>   
4 3     <chr [1]>

null_list <- null_list[!unlist(lapply(null_list$value, is.null)),]

null_list

> null_list
# A tibble: 1 x 2
  name  value    
  <chr> <list>   
1 3     <chr [1]>

Upvotes: 1

Onyambu
Onyambu

Reputation: 79288

In Base R, you could do:

null_list[colSums(sapply(null_list,lengths))>0]
# A tibble: 3 x 1
   name
  <int>
1     1
2     2
3     3

You could also use select_if from tidyverse

 library(tidyverse)
 null_list %>%
    select_if(map_lgl(.,~sum(lengths(.x))>0))
# A tibble: 3 x 1
   name
  <int>
1     1
2     2
3     3

Upvotes: 1

Related Questions