Skip to content

Instantly share code, notes, and snippets.

@mpettis
Last active December 12, 2018 01:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpettis/8a34a1dbc0f2f07e65352138c5b45790 to your computer and use it in GitHub Desktop.
Save mpettis/8a34a1dbc0f2f07e65352138c5b45790 to your computer and use it in GitHub Desktop.
# Dealing with NULLs as list values
library(tidyverse)
# As advertised on the tin:
is.null(NULL)
#> [1] TRUE
# is.null() is not vectorized?
is.null(list(NULL))
#> [1] FALSE
# And you can't vectorize it over a list
Vectorize(is.null)(list(NULL, NULL))
#> [1] FALSE
# But it can be mapped over
list(NULL, NULL) %>% map_lgl(is.null)
#> [1] TRUE TRUE
# Make a nested list, with some nulls
lstt <- list(parms = list(a=1, b=NULL, c="LETTER"), b=2, c=NULL, d="four")
# nulls are kept as entries
lstt %>% str()
#> List of 4
#> $ parms:List of 3
#> ..$ a: num 1
#> ..$ b: NULL
#> ..$ c: chr "LETTER"
#> $ b : num 2
#> $ c : NULL
#> $ d : chr "four"
# But I lose nulls when I unlist them
unlist(lstt)
#> parms.a parms.c b d
#> "1" "LETTER" "2" "four"
# I can recurse over list if I know what I am doing...
rapply(lstt, is.numeric) # All FALSE, because again, NULLS lost
#> parms.a parms.c b d
#> TRUE FALSE TRUE FALSE
rapply(lstt, function(x) x) # Identity function, still loses nulls
#> parms.a parms.c b d
#> "1" "LETTER" "2" "four"
# Alas, `rapply` can't be coerced to do this stuff.
# Here is a solution:
# https://stackoverflow.com/questions/38950005/how-to-manipulate-null-elements-in-a-nested-list
replaceInList <- function (x, FUN, ...) {
if (is.list(x)) {
for (i in seq_along(x)) {
x[i] <- list(replaceInList(x[[i]], FUN, ...))
}
x
}
else FUN(x, ...)
}
replaceInList(lstt, function(x) if (is.null(x)) NA else x) %>%
unlist()
#> parms.a parms.b parms.c b c d
#> "1" NA "LETTER" "2" NA "four"
# And added bonus, flattening list and returning data frame
replaceInList(lstt, function(x) if (is.null(x)) NA else x) %>%
unlist() %>%
enframe() %>%
spread(name, value)
#> # A tibble: 1 x 6
#> b c d parms.a parms.b parms.c
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 2 <NA> four 1 <NA> LETTER
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment