1

I have this data frame

library(tidyverse)
df <- structure(list(D1_step1 = c("FT", "FF", "FF", "TTT", "FFF", "FFF", 
      "FF", "FFF", "FT", "TT"), barrido = c("B1_B4", "B1_B2", "B1_B4", 
      "B1_B2_B4", "B1_B2_B4", "B1_B2_B4", "B1_B4", "B1_B2_B4", "B1_B4", 
      "B1_B4")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
      -10L))

AND this function

f1 <- function(sero, barrido){
  as.logical(case_when(str_detect(barrido, "B1") ~ str_sub(sero, 1, 1)))
}

df %>%
mutate(new_col = f1(D1_step1, barrido))

I do this and it works fine. I don't need the barrido argument in the function as this does not vary and the the data always has a column named 'barrido'. Thus I'd like to do this....

f2 <- function(sero){
  as.logical(case_when(str_detect(barrido, "B1") ~ str_sub(sero, 1, 1)))
}

df %>%
mutate(new_col = f2(D1_step1))

 Error in stri_detect_regex(string, pattern, negate = negate, opts_regex = opts(pattern)) : 
  object 'barrido' not found

but computer says no so I tried setting the argument as a default and I got a different kind of no. Nb just edited this as I hadn't actually set the argument as default originally

f3 <- function(sero, barrido = barrido){
  as.logical(case_when(str_detect(barrido, "B1") ~ str_sub(sero, 1, 1)))
}

df %>%
mutate(new_col = f3(D1_step1))

 Error in stri_detect_regex(string, pattern, negate = negate, opts_regex = opts(pattern)) : 
  promise already under evaluation: recursive default argument reference or earlier problems?

Writing a custom case_when function to use in dplyr mutate using tidyeval. This question doesn't help as I don't want to write the function as a case_when within a mutate. The comments below give an indication as to why this not working and lead me to believe that there may be a solution using tidyeval. Also I am curious as to what is behind the difference between the error messages between f2 and f3.

hammoire
  • 341
  • 1
  • 2
  • 10
  • 1
    Functions are independent, they are not "attached" to your dataframe. So you can also use `f1(1:10, 11:20)` without any error. (I know it doesn't make sense but just for demonstrating). Also `sero` and `barrido` are just variables, you can replace them with `a` and `b` in `f1` and it will still work. So when you are using `barrido` in the function it's definition should be present somewhere in the function itself (or in global environment). – Ronak Shah Feb 28 '20 at 02:26
  • So you want the function to always use the values of `barrido` in the dataframe where it's being called? There are ways to do this, e.g. you could write the function to accept a dataframe as input rather than individual vectors, but I'm not sure it would be any cleaner than just passing the values of `barrido`. – Marius Feb 28 '20 at 02:42
  • @RonakShah. But when I call the function I am using dplyr::mutate which uses NSE so I thought that the dataframe and its variables including 'barrido' are available in the environment of the function call. Maybe I'm wrong. – hammoire Feb 28 '20 at 02:56
  • @Marius yes. I don't want the function to accept a data frame (i.e. wrap a mutate around it) as it makes naming the new variables hard – hammoire Feb 28 '20 at 02:58
  • No, as I said functions are independent. They don't know from where they are called. For example for `sum` function. It works with `sum(mtcars$mpg)` and also `sum(1:10)`. The functions which you have defined are the same. – Ronak Shah Feb 28 '20 at 03:02
  • @RonakShah Ok thank you understood. would be good to know if there is a NSE or tidy eval way to handle this then. – hammoire Feb 28 '20 at 14:07

1 Answers1

1

With the development version of dplyr (to be released as dplyr 1.0) you can peek at the current columns with across().

f2 <- function(sero){
  barrido <- across(all_of("barrido"))[[1]]
  as.logical(case_when(
    str_detect(barrido, "B1") ~ str_sub(sero, 1, 1)
  ))
}

It should be clearly documented that this function only works inside dplyr with data frames containing a barrido column.

Lionel Henry
  • 6,652
  • 27
  • 33