Search code examples
rfunctionrlang

curly-curly braces - why won't this function accept an unquoted variable


Can someone help me see where I'm going wrong? I thought when using curly-curly braces in a piped function that you could call the variable without having to enclose it in "" (i.e. as a string). So where is my function going wrong:

library(tidyverse)
dat <-  structure(list(id = 1:6, 
                       var_1 = c("1,1,-11000", "1,1,1", "0,0,0", "1,1,0", "1,1,1", "1,1,1"), 
                       var_2 = c("0,0,-13000", "0,0,0", "-13000,-13000,-13000", "6,4,-13000", "0,0,0", "0,0,0"), 
                       var_3 = c("24,7,-13000", "0,0,0", "-13000,-13000,-13000", "0,0,-13000", "0,0,0", "0,0,0")), 
                  row.names = 1:6, class = "data.frame")

# Separate to wide and convert to long in one step
split_to_long <-  function(col){
  i <-  substr({{col}}, 5, 5)
  temp <-  dat |>
    select("id", {{col}}) |>
    separate_wider_delim({{col}}, ",", too_few = "align_start",
                         names = c(paste0({{col}},"_1"),
                                   paste0({{col}},"_2"),
                                   paste0({{col}},"_3"))) |>
    pivot_longer(2:4,
                 names_to = "visit",
                 values_to = paste0("var_", i),
                 names_prefix = paste0("var_", i, "_"))
  temp
}

# This works
split_to_long("var_1")

# But this doesn't
split_to_long(var_1)

This comes from another question I posted: How to replace this for loop with purrr::map


Solution

  • If you want both to work, you can make a few modifications to your code, using the substitute function. I also suggest including a data argument to your function.

    split_to_long <-  function(data, col){
    
      col_i <- substitute(col)
      i <-  substr(col_i, 5, 5)
      
      temp <-  data |>
        select(id, {{col}}) |>
        separate_wider_delim({{col}}, ",", too_few = "align_start",
                             names = c(paste0(col_i,"_1"),
                                       paste0(col_i,"_2"),
                                       paste0(col_i,"_3"))) |>
        pivot_longer(2:4,
                     names_to = "visit",
                     values_to = paste0("var_", i),
                     names_prefix = paste0("var_", i, "_"))
      temp
    }
    
    res1 <- split_to_long(dat, "var_1")
    res2 <- split_to_long(dat, var_1)
    
    identical(res1, res2)
    [1] TRUE