1

I am trying to create a suite of dynamically named new objects (e.g., temp2015) using a for loop, and storing dynamic values - specifically, the names of other objects (e.g., Y2015) and the value used in the for loop (e.g., 2015) - in the dynamically named new objects.

I am not sure why the code below is not working.

Y2015 = data.frame(VAR1 = 6:10, VAR2 = 1:5)
Y2016 = data.frame(VAR1 = 7:11, VAR2 = 11:15)
Y2017 = data.frame(VAR1 = 7:11, VAR3 = 5:9, VAR4 = 4:8)

for (i in 2015:2017) {
  paste0("temp", i) <- cbind(names(paste0("Y", i)), i)
}

all <- rbind(temp2015, temp2016, temp2017)

The code below gets the result I want (specifically, the data content in the object all_manual) but this was done manually, on a very small sample dataset, and isn't a long-term solution.

Y2015 = data.frame(VAR1 = 6:10, VAR2 = 1:5)
Y2016 = data.frame(VAR1 = 7:11, VAR2 = 11:15)
Y2017 = data.frame(VAR1 = 7:11, VAR3 = 5:9, VAR4 = 4:8)

all_manual = data.frame(file = c('VAR1', 'VAR2', 'VAR1', 'VAR2', 'VAR1', 'VAR3', 'VAR4'),
                 year = c(2015, 2015, 2016, 2016, 2017, 2017, 2017))

I'd greatly appreciate any advice or ideas about how to get this working.

  • What you are requesting is the use of `assign` and `get`, and you will find a significant amount of opposition to using those functions: they almost always indicate poor design. Since the frames all look the same I suggest you look into using a [list of frames](https://stackoverflow.com/a/24376207/3358272): since you're likely to do the same or similar things to each frame, the use of `lapply` can greatly simplify the maintainability/flexibility of your code. – r2evans Oct 23 '20 at 14:48

2 Answers2

0

You can use mget and stack

# creates a list of all objects with names starting with "Y" followed by 4 digits
l <- mget(x = ls(pattern = "^Y\\d{4}$"))

Now use stack to create a dataframe from the names of that list and the columns names of the dataframes that the list contains

out <- stack(sapply(l, names))

Result

out 
#  values   ind
#1   VAR1 Y2015
#2   VAR2 Y2015
#3   VAR1 Y2016
#4   VAR2 Y2016
#5   VAR1 Y2017
#6   VAR3 Y2017
#7   VAR4 Y2017

If you wish to remove the "Y" and make the ind to numeric, try

out$ind <- as.numeric(sub("Y", "", out$ind))

Change column names

names(out) <- c("file", "year")
out
#   file year
#1 VAR1 2015
#2 VAR2 2015
#3 VAR1 2016
#4 VAR2 2016
#5 VAR1 2017
#6 VAR3 2017
#7 VAR4 2017
markus
  • 25,843
  • 5
  • 39
  • 58
0

Solution of markus recommended. But in case you wish to use a for loop.

for(i in 2015:2017){
  df <- get(paste("Y",i, sep = ""))
  df1 <- as.data.frame(cbind(colnames(df), i))
  if(i == lower_year){result <- df1} else{result <- rbind(result,df1)}
  }

maarvd
  • 1,254
  • 1
  • 4
  • 14