1

I'm trying to get a for loop to generate multiple smaller dataframes from a large dataframe:

Year <- rep(1995:2012,4)
Name <- rep(LETTERS[1:4],18)
abc <- data.frame(Year,Name)


for (year in 1995:2012) {
  assign(paste("dff",year,sep=""), abc[abc$Year == year,])
  #paste("dff",year,sep="") <- paste("dff",year,sep="")[with(paste("dff",year,sep=""), order(Name)), ]
}

Problem is the last (commented) line which when uncommented throws an error:

invalid 'envir' argument of type 'character'.

What can I do to fix this? I'm basically trying to order the dataframe by the column Name.

wwl
  • 1,757
  • 1
  • 18
  • 46

2 Answers2

2

Either you use list() or adapt your code the following way:

Year <- rep(1995:2012,4)
Name <- rep(LETTERS[1:4],18)
abc <- data.frame(Year,Name)


for (year in 1995:2012) {
  assign(paste("dff",year,sep=""), abc[abc$Year == year,])
  assign((paste("dff",year,sep="")), get(paste("dff",year,sep=""))[with(get(paste("dff",year,sep="")), order(Name)), ])
}
Tonio Liebrand
  • 15,033
  • 3
  • 27
  • 48
2

Just in the interest of providing a couple of extra options, or If you were interested in using lists, and or avoiding using assign we could do the following:

library(data.table)

Year <- rep(1995:2012,4)
Name <- rep(LETTERS[1:4],18)
abc <- data.frame(Year,Name)

abc <- data.table(abc)
my_list <- split(abc, Year)
my_list <- lapply(my_list, function(x){x[order(Name)]})

Pretty simple, avoids using get and assign. split gets rid of the need to loop things to split the data table up as well. Might be easier to read/understand too.

If you wanted to stick to something using a for loop, i.e. what you had initially, you could do:

empty_list <- list()

for(i in unique(abc[,Year])){
  empty_list[[paste0(i)]] <- abc[Year == i,]
  empty_list[[paste0(i)]] <- empty_list[[paste0(i)]][order(Name)]
}

Someone might be able to write a cleaner loop than above, but it works!

Gin_Salmon
  • 757
  • 1
  • 6
  • 18