Search code examples
rdplyrpurrranonymous-functiontidyeval

tidyeval: !! with purrr::map anonymous functions


I would like to create a single column by conditional logic across multiple columns. This is a minimal reproducible example. As you can see, the double bang seems to cause evaluation of the .x before the anonymous function is defined. Any ideas for a solution on this one that would allow me to map over a list of targets?

library(magrittr)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
df <- data.frame(
  stringsAsFactors = FALSE,
  Well.Position = c("C23", "C24", "D23", "D24"),
  S = c(28.65475574, 28.06971218, 28.04204381, 29.45081936),
  N = c(29.67113762, 29.65467395, 30.00612006, 29.65156431)
)

targets <- c("S", "N")
# works
df %>% 
  dplyr::mutate(PASS =  !!sym(targets[1]) <= 37)
#>   Well.Position        S        N PASS
#> 1           C23 28.65476 29.67114 TRUE
#> 2           C24 28.06971 29.65467 TRUE
#> 3           D23 28.04204 30.00612 TRUE
#> 4           D24 29.45082 29.65156 TRUE
# does not work
df %>% 
  dplyr::mutate(PASS = all(purrr::map_lgl(targets, ~ (!!sym(.x) <= 37))))                
#> Error in is_symbol(x): object '.x' not found

Solution

  • You can use if_any -

    library(dplyr)
    
    df %>% mutate(PASS = if_any(all_of(targets), ~.x <= 37))
    
    #  Well.Position        S        N PASS
    #1           C23 28.65476 29.67114 TRUE
    #2           C24 28.06971 29.65467 TRUE
    #3           D23 40.00000 30.00612 TRUE
    #4           D24 29.45082 29.65156 TRUE