Search code examples
rfunctiondplyrindirection

Is it possible to use indirection with base R?


Question: Is there a better way to indirectly reference a data variable in a function when using base R?

Example Setup

I have a dataframe that I want to loop through some column (will vary in name) and build a string. This is simplified, but illustrates the approach:

library(tidyverse)

df_original <- data.frame(id = 1:3, string = c("dog", "cat", "mouse"))
df_original

> df_original
  id string
1  1    dog
2  2    cat
3  3  mouse

# Easily can build string using base R with loop like this:
for (i in 1:nrow(df_original)){
  print(paste("I love my pet", df_original[i, "string"]))
}

[1] "I love my pet dog"
[1] "I love my pet cat"
[1] "I love my pet mouse"

Problem:

I want to put this in a function with the ability to map different column names to the data-variable. I was looking at "indirection", which I've used when writing function in DPLYR, but this doesn't work (and I expected that):

# Want to apply same idea inside function where df's column names may change,
# so I need to be able to quote them, but I know this is wrong.
myfun <- function(df, var){
  for (i in 1:nrow(df)){
    print(paste("I love my pet", df[i, {{var}}]))
  }
}

# This fails:
myfun(df_original, string)

Error: object 'string' not found

Works, but would like to do better:

I can rename() (DPLYR verb) the dataframe at the start of the function -- as seen below -- and get where I want, but this is a fuzzy area of R for me, and I'm hoping someone can explain how I might achieve that result in base R. My actual use case (not this simplified example) has me building URL GET requests using lat/longs for origin/destination combinations, and the four columns are never consistently named in the source dataframes.

# Can rename the variable locally in the function, then use, but 
# this seems clunky.
myfun2 <- function(df, var){
  df <- rename(df, var = {{var}})
  for (i in 1:nrow(df)){
    print(paste("I love my pet", df[i, "var"]))
  }
}

# But it does work:
myfun2(df_original, string)

> myfun2(df_original, string)
[1] "I love my pet dog"
[1] "I love my pet cat"
[1] "I love my pet mouse"

I appreciate any suggestions. Thank you.


Solution

  • myfun <- function(df, var){
         paste("I love my pet", eval(substitute(var), df))
    }
    myfun(df_original, string)
    [1] "I love my pet dog"   "I love my pet cat"   "I love my pet mouse"
    

    myfun <- function(df, var){
         paste("I love my pet", df[,deparse(substitute(var))])
    }
    myfun(df_original, string)
    [1] "I love my pet dog"   "I love my pet cat"   "I love my pet mouse"
    

    Edit:

     myfun <- function(df, var){
       var <- deparse(substitute(string))
       for (i in 1:nrow(df)){
         print(paste("I love my pet", df[i, var]))
       }
     }
     myfun(df_original, string)
    [1] "I love my pet dog"
    [1] "I love my pet cat"
    [1] "I love my pet mouse"