Create dynamic R dataframe names in for loop - multiple names in same code line

Viewed 837

I am trying to create dynamic dataframe names within a for loop. I am using the paste function in R to write the dataframe names. see the example below:

for (i in 1:3){
 paste("Data",i,sep="") <- data.frame(colone=c(1,2,3,4),coltwo=c(5,6,7,8))
 paste("New data",i,sep="") <- paste("Data",i,sep="") %>% mutate(colthree=(colone+coltwo)*i) %>% select(colthree)
}

The code above won't work as R doesn't understand paste as a dataframe name. I have found some solutions using the assign function which could help with my 1st line of code using: assign(paste("Data",i,sep=""),data.frame(colone=c(1,2,3,4),coltwo=c(5,6,7,8))) but I don't know what to do with the 2nd line where the paste function is used twice to refer to multiple dataframes. Not sure using a nested assign function works and even if it does the code will look terrible with more complex code.

I know there might be ideas of how to combine the 2 lines above into a single assign statement or other similar solutions but is there any way to refer to 2 dynamic dataframe names within a single line of code as per my example above?

Many thanks :)

2 Answers

This seems to be working but it's a little bit convoluted:

library(tidyverse)
library(stringr)
library(rlang)
#> 
#> Attaching package: 'rlang'
#> The following objects are masked from 'package:purrr':
#> 
#>     %@%, as_function, flatten, flatten_chr, flatten_dbl, flatten_int,
#>     flatten_lgl, flatten_raw, invoke, list_along, modify, prepend,
#>     splice



i <- seq(1, 3, 1) #how many loops

pwalk(list(paste("Data",i,sep=""), paste("New_data",i,sep=""), i), ~{
    assign(..1, data.frame(colone=c(1,2,3,4),coltwo=c(5,6,7,8)), envir = .GlobalEnv)
    new <-  sym(..1) #convert a string to a variable name
    assign(..2, {eval_tidy(new)%>% mutate(colthree=(colone+coltwo)*..3) %>% select(colthree)}, envir = .GlobalEnv) 
    
})

names(.GlobalEnv)
#> [1] "Data1"     "Data2"     "Data3"     "i"         "New_data1" "New_data2"
#> [7] "New_data3"

Data1
#>   colone coltwo
#> 1      1      5
#> 2      2      6
#> 3      3      7
#> 4      4      8
New_data1
#>   colthree
#> 1        6
#> 2        8
#> 3       10
#> 4       12

Created on 2021-06-10 by the reprex package (v2.0.0)

If you need both data frames ("Data i" and "New Data i") you can use:

for (i in 1:3){
  assign(paste("New data",i,sep=""), data.frame(assign(paste("Data",i,sep=""),data.frame(colone=c(1,2,3,4),coltwo=c(5,6,7,8))) %>% mutate(colthree=(colone+coltwo)*i) %>% select(colthree)))
}

If you only want "New Data i" use:

for (i in 1:3){
  assign(paste("New data",i,sep=""), data.frame(colone=c(1,2,3,4),coltwo=c(5,6,7,8))) %>% mutate(colthree=(colone+coltwo)*i) %>% select(colthree)
}
Related