Reputation: 363
I want to write a function, which takes symbolic names of columns and pass it to subsequent functions doing something specific (sub-tasks).
Let me show you an example:
The data:
> ( d <- data.frame(A=1:3, B=3:1) )
A B
1 1 3
2 2 2
3 3 1
Now my function:
fn <- function(data, cols) {
return(data %>% mutate(across({{cols}}, ~. * 2)))
}
It works:
> d %>% fn(A)
A B
1 2 3
2 4 2
3 6 1
Now, suppose this function does something important and separable as a unit task. Now I want to use this function in another function, taking column names in the dplyr-way:
another_fn <- function(data, cols) {
result <- data %>% fn(cols)
# .... more code
return(result)
}
This doesn't work.
> d %>% another_fn(cols = A)
Error: Problem with `mutate()` input `..1`.
x object 'A' not found
i Input `..1` is `across(cols, ~. * 2)`.
Run `rlang::last_error()` to see where the error occurred.
When I provide the column as a string, it works well. So I understand the context is lost somewhere when I provide just the symbolic name A
> d %>% another_fn(cols = "A")
Note: Using an external vector in selections is ambiguous.
i Use `all_of(cols)` instead of `cols` to silence this message.
i See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
A B
1 2 3
2 4 2
3 6 1
My question is: how to pass the symbolic name across nested calls?
Please note, I DO NOT WANT using three-dot (ellipsis) operator. I DO WANT to control what I pass and to which variable.
EDIT:
OK, I found the answer. The {{ }} should be added in the nested calls
another_fn <- function(data, cols) {
result <- data %>% fn({{cols}})
# .... more code
return(result)
}
> d %>% another_fn(cols = A)
A B
1 2 3
2 4 2
3 6 1
> d %>% another_fn(cols = "A")
A B
1 2 3
2 4 2
3 6 1
> column
[1] "A"
> d %>% another_fn(cols = column)
A B
1 2 3
2 4 2
3 6 1
>
Upvotes: 0
Views: 164
Reputation: 206207
Just use {{}}
as you did in the first function
another_fn <- function(data, cols) {
result <- data %>% fn({{cols}})
return(result)
}
Upvotes: 1