My goal is to write a pipeable function which applies a (custom) function to a specified column; when the column is missing the original dataframe is returned (without any error/warning). In this example the floor() function is used as simple example.
The suggested solution is not handling the case when a column is missing.
> mtcars %>% head(5) %>% floor_if_not_missing(miles_per_gallon)
Error: Problem with `mutate()` input `..1`.
x Can't subset columns that don't exist.
x Column `miles_per_gallon` doesn't exist.
The suggested solution is working general, but doesn't solve one of the goals: to be able to select dynamically a column, because the matches() expects a character vector.
Continuing on your idea, the following can be a solution:
I'd use any_of() instead of matches() as matches() looks for a regular expression. So if someone had a column name that was a regular expression you might get unexpected results. E.g.
library(tidyverse)
floor_if_not_missing_matches <- function(df, col_name){
col_name <- rlang::as_label(rlang::enquo(col_name))
df %>% mutate(across(matches(col_name), floor))
}
floor_if_not_missing_any_of <- function(df, col_name){
col_name <- rlang::as_label(rlang::enquo(col_name))
df %>% mutate(across(any_of(col_name), floor))
}
# this floors both mpg and m.
mtcars %>%
select(mpg) %>%
mutate(m. = mpg) %>%
head(3) %>%
floor_if_not_missing_matches(m.)
#> mpg m.
#> Mazda RX4 21 21
#> Mazda RX4 Wag 21 21
#> Datsun 710 22 22
# this only floors m.
mtcars %>%
select(mpg) %>%
mutate(m. = mpg) %>%
head(3) %>%
floor_if_not_missing_any_of(m.)
#> mpg m.
#> Mazda RX4 21.0 21
#> Mazda RX4 Wag 21.0 21
#> Datsun 710 22.8 22
# and to confirm original behaviour still works
mtcars %>%
select(mpg) %>%
mutate(m. = mpg) %>%
head(3) %>%
floor_if_not_missing_any_of(h.)
#> mpg m.
#> Mazda RX4 21.0 21.0
#> Mazda RX4 Wag 21.0 21.0
#> Datsun 710 22.8 22.8