0

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
> 
Bastian
  • 313
  • 1
  • 13
  • You shouldn't edit your question to include an answer. If you want to answer your own question, do so by posting an answer below so the question can be marked as answered. Then other people are free to post alternate solutions as well and the community can properly vote as well. – MrFlick Dec 21 '20 at 07:21

1 Answers1

1

Just use {{}} as you did in the first function

another_fn <- function(data, cols) {
  result <- data %>% fn({{cols}})
  
  return(result)
}
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • That's right. I found this a minute after publishing my post. I edited it with the solution. Thank you for your response! – Bastian Dec 21 '20 at 07:22