Reputation: 1293
in short:
Can you use !!!
splicing and a list input for case_when
inside of a mutate
, and how?
As mentioned in an answer to previous question as of dplyr >0.7.0 you can use bare variable names inside a case_when()
inside of a mutate()
Next to that, in the help file for case_when
it shows how you can use a list of patterns and !!!
like so: (patterns is the wrong way around, with general case first, but that is the case in the actual documentation and doesn't matter for my issue)
x <- 1:50
patterns <- list(
TRUE ~ as.character(x),
x %% 5 == 0 ~ "fizz",
x %% 7 == 0 ~ "buzz",
x %% 35 == 0 ~ "fizz buzz"
)
case_when(!!! patterns)
However, combining these approaches doens't seem to work:
testframe <- tibble(y = 1:50) #Switching to y so the x from earlier can't interfere
testframe2 <- testframe %>%
mutate(
fizzbuzz = case_when(
y %% 35 == 0 ~ "fizz buzz",
y %% 5 == 0 ~ "fizz",
y %% 7 == 0 ~ "buzz",
TRUE ~ as.character(y)
)
)
patterns <- list(
y %% 35 == 0 ~ "fizz buzz",
y %% 5 == 0 ~ "fizz",
y %% 7 == 0 ~ "buzz",
TRUE ~ as.character(y)
)
testframe3 <- testframe %>%
mutate(
fizzbuzz = case_when(
!!!(patterns)
)
)
testframe2 will work fine, whilst testframe3 gives the following error:
Error in mutate_impl(.data, dots) :
Evaluation error: object 'y' not found.
I'm assuming there's some NSE magic at work here, but I haven't managed to quo()
my way out of this. I did look at the quo()
s of testframe2 and 3 (a debugging approach suggested in the programming with dplyr vignette). I noticed they are the same:
testframe2quo <- quo(testframe %>%
mutate(
fizzbuzz = case_when(
y %% 35 == 0 ~ "fizz buzz",
y %% 5 == 0 ~ "fizz",
y %% 7 == 0 ~ "buzz",
TRUE ~ as.character(y)
)
)
)
testframe3quo <- quo(testframe %>%
mutate(
fizzbuzz = case_when(
!!!(patterns)
)
)
)
testframe2quo
<quosure: global>
~testframe %>% mutate(fizzbuzz = case_when(y%%35 == 0 ~ "fizz buzz",
y%%5 == 0 ~ "fizz", y%%7 == 0 ~ "buzz", TRUE ~ as.character(y)))
testframe3quo
<quosure: global>
~testframe %>% mutate(fizzbuzz = case_when(y%%35 == 0 ~ "fizz buzz",
y%%5 == 0 ~ "fizz", y%%7 == 0 ~ "buzz", TRUE ~ as.character(y)))
all of which brings me back to my question:
Can you use !!!
splicing and a list input for case_when
inside of a mutate
, and how?
Upvotes: 2
Views: 1287
Reputation: 7830
You should wrap your cases in exprs
instead of list
and use the prefix .data
patterns <- rlang::exprs(
.data$y %% 35 == 0 ~ "fizz buzz",
.data$y %% 5 == 0 ~ "fizz",
.data$y %% 7 == 0 ~ "buzz",
TRUE ~ as.character(.data$y)
)
mutate(testframe, fizzbuzz = case_when(!!! patterns))
Upvotes: 3