Home > Blockchain >  Passing columns with ... to function that mutates over several columns
Passing columns with ... to function that mutates over several columns

Time:10-01

I would like to write a function that mutates user named columns. In the first instance, I would like to pass them as strings, but am also interested to know how to do this with column names.

I have found a working method for string arguments with unlist(list(...)), but I suspect that there is a neater way of doing this.

Here is the example

data <- tibble(
  a = 1:10,
  b = 21:30,
  c = 101:110
)

#working but messy

test_strings <- function(data, ...) {
  data %>%
    mutate_at(unlist(list(...)),
              function(x){x 5})
}

test_strings(data, "a", "b")

# A tibble: 10 x 3
# a     b     c
# <dbl> <dbl> <int>
# 1     6    26   101
# 2     7    27   102
# 3     8    28   103
# 4     9    29   104
# 5    10    30   105
# 6    11    31   106
# 7    12    32   107
# 8    13    33   108
# 9    14    34   109
# 10    15    35   110

#not working
test_sym <- function(data, ...) {
  data %>%
    mutate_at(c(...),
              function(x){x 5})
}

test_sym(data, a, b)
#Error in check_dot_cols(.vars, .cols) : object 'b' not found

CodePudding user response:

We can use across

test_strings <- function(data, ...) {
  data %>%
    mutate(across(all_of(c(...)),
               ~ .x   5))
}

-testing

> test_strings(data, "a", "b")
# A tibble: 10 × 3
       a     b     c
   <dbl> <dbl> <int>
 1     6    26   101
 2     7    27   102
 3     8    28   103
 4     9    29   104
 5    10    30   105
 6    11    31   106
 7    12    32   107
 8    13    33   108
 9    14    34   109
10    15    35   110

If we want a general case, capture as symbols and convert to string

test_general <- function(data, ...) {
  colnms <- purrr::map_chr(ensyms(...), rlang::as_string)
  data %>%
    mutate(across(all_of(colnms),
               ~ .x   5))
  
}

-testing

> test_general(data, a, b)
# A tibble: 10 × 3
       a     b     c
   <dbl> <dbl> <int>
 1     6    26   101
 2     7    27   102
 3     8    28   103
 4     9    29   104
 5    10    30   105
 6    11    31   106
 7    12    32   107
 8    13    33   108
 9    14    34   109
10    15    35   110
> test_general(data, "a", "b")
# A tibble: 10 × 3
       a     b     c
   <dbl> <dbl> <int>
 1     6    26   101
 2     7    27   102
 3     8    28   103
 4     9    29   104
 5    10    30   105
 6    11    31   106
 7    12    32   107
 8    13    33   108
 9    14    34   109
10    15    35   110
  • Related