Tea Tree
Tea Tree

Reputation: 984

Preventing purrr::map error when function returns NULL

I'd like to use the map_chr function on a dataset like so

library(purrr)
library(dplyr)

f <- function(x) if(x == "a") NULL else "blah"
f("a") # returns NULL

# make tibble
mytib <- tibble(test = c("a", "b"))

# naive map_chr
mytib %>% mutate(getf = map_chr(test, f))

# with .default
mytib %>% mutate(getf = map_chr(test, f, .default = NA_character_))

As you can see, map_chr fails with error message Error: Problem with `mutate()` input `getf`. x unused argument (.default = NA).

Attempts with possibly and na_if as described elsewhere didn't work for me either.

How can I get map_chr to loop over the arguments and leave NULL values to be NA_character_ or some other value?

Upvotes: 1

Views: 1993

Answers (2)

Angel F. Escalante
Angel F. Escalante

Reputation: 133

purrr::map_chr() will try to convert the list output to a character vector, if you try to convert a NULL object to a character you get something like this:

as.character(NULL)
#> character(0)

Which is a vector with length 0. Moreover, NULL is not valid object type for this function. By the other hand, this is what you get if try to convert a NA_character_ to character..

as.character(NA_character_)
#> NA

You can try this:

library(purrr)

f <- function(x) if(x == "a") NA_character_ else "blah"

# make tibble
mytib <- tibble(test = c("a", "b"))

# naive map_chr
mytib %>% mutate(getf = map_chr(test, f))
## A tibble: 2 x 2
#  test  getf 
#  <chr> <chr>
#1 a     NA   
#2 b     blah

Upvotes: 0

akrun
akrun

Reputation: 887511

It may be better to define the f to return NA_character_

 f <- function(x) if(x == "a") NA_character_ else "blah"

and then the OP's call works as expected

Or instead of looping, create a vectorized function

f <- function(x) case_when(x != 'a' ~ 'blah')

and then call as

mytib %>% 
       mutate(getf = f(test))

Or another option if the f is already defined to return NULL, then concatenate with NA and extract the first element. NULL doesn't have any length, so concatenating with NA returns NA only

c(NULL, NA_character_)
#[1] NA

mytib %>% 
   mutate(getf = map_chr(test, ~ c(f(.x), NA_character_)[1]))
# A tibble: 2 x 2
#  test  getf 
#  <chr> <chr>
#1 a     <NA> 
#2 b     blah 

The [1] index is to extract those cases where there is actual values 'blah' returns, so that we select only the first element i.e. 'blah' and for those with if condition is TRUE, it will anyway return only NA_character_

Upvotes: 1

Related Questions