James N
James N

Reputation: 325

purrr::possibly function possibly not working with map2_chr function

I suspect that this is a bug in the purrr package, but would like to check my logic in StackOverflow first, please.

It seems to me that the possibly function is not working inside the map2_chr function. I'm using purrr version 0.2.5

Consider this example:

library(dplyr)
library(purrr)

lets <- tibble(posn = 2:0,
               lets_list = list(letters[1:5], letters[1:5], letters[1:5])) %>% 
  glimpse()

returns

Observations: 3
Variables: 2
$ posn      <int> 2, 1, 0
$ lets_list <list> [<"a", "b", "c", "d", "e">, <"a", "b", "c", "d", "e">, <"a", "b", "c", "d", "e">]

In this example, I want to create another column using mutate to return the element in the list "lets_list" based on the value in "posn".

lets %>% 
  mutate(lets_sel = map2_chr(lets_list, posn, ~.x[.y]))

fails with this error message as the third row have posn = 0.

> lets %>% 
+   mutate(lets_sel = map2_chr(lets_list, posn, ~.x[.y]))
#    Error in mutate_impl(.data, dots) : 
#      Evaluation error: Result 3 is not a length 1 atomic vector.

Using the possibly function with map2_chr returns an error too.

lets %>% 
  mutate(lets_sel = map2_chr(lets_list, posn, possibly(~.x[.y], NA_character_)))
# Error in mutate_impl(.data, dots) : 
#  Evaluation error: Result 3 is not a length 1 atomic vector.

However, the map2 function works fine:

> lets %>% 
+   mutate(lets_sel = map2(lets_list, posn, possibly(~.x[.y], NA_character_)))
# A tibble: 3 x 3
   posn lets_list lets_sel 
  <int> <list>    <list>   
1     2 <chr [5]> <chr [1]>
2     1 <chr [5]> <chr [1]>
3     0 <chr [5]> <chr [0]>

A workaround solution is to use map2 and then map_chr, but I suspect that this is a bug.

> lets %>% 
+   mutate(lets_sel = map2(lets_list, posn, ~.x[.y]),
+          lets_sel = map_chr(lets_sel, possibly(~.x[1], NA_character_)))
    # A tibble: 3 x 3
       posn lets_list lets_sel
      <int> <list>    <chr>   
    1     2 <chr [5]> b       
    2     1 <chr [5]> a       
    3     0 <chr [5]> NA      

Am I missing something here? Thanks.

Upvotes: 2

Views: 1541

Answers (2)

Mikko Marttila
Mikko Marttila

Reputation: 11908

possibly() doesn't work because indexing with 0 doesn't throw an error; it just returns a length 0 vector:

nth_letter <- function(n) letters[n]

possibly(nth_letter, "not returned")(0)
#> character(0)

nth_letter(0)
#> character(0)

In this case it would probably be easier to replace invalid indices with NA (using e.g. dplyr::na_if(), or plain old ifelse if the real problem is more complex) to get what you are after:

lets %>% 
  mutate(lets_sel = map2_chr(lets_list, na_if(posn, 0), ~ .x[.y]))
#> # A tibble: 3 x 3
#>    posn lets_list lets_sel
#>   <int> <list>    <chr>   
#> 1     2 <chr [5]> b       
#> 2     1 <chr [5]> a       
#> 3     0 <chr [5]> <NA>

Created on 2018-08-07 by the reprex package (v0.2.0.9000).

Upvotes: 0

James N
James N

Reputation: 325

OK, now I'm thinking that this is just a "feature". The most elegant solution / workaround is just:

lets %>% 
  mutate(lets_sel = map2(lets_list, posn, ~.x[.y]) %>% 
           map_chr(., possibly(~.x[1], NA_character_)))

Nowhere in the help screen suggests that safely and possibly can by used with the map2 family of functions. Hence I conclude that this is a "feature" rather than a "bug".
Thanks.

Upvotes: 1

Related Questions