mcjudd
mcjudd

Reputation: 1580

R: Accessing and using names of data.frames within a list during an `apply` function

I'm trying to write a function that takes a list of data.frames (somelist) and writes them out to .csv files, each named the same as the data.frame being written (i.e., a1.csv, a2.csv, a3.csv).

somelist <- list(a1 = data.frame(a = 1, b = 2, c = 3),
                 a2 = data.frame(d = 4, e = 5, f = 6),
                 a3 = data.frame(g = 7, h = 8, i = 9))

csvout <- function (y) {
    z <- deparse(substitute(y))
    write.table(y, file = paste0("~/somefolder/",
                                 z,
                                 ".csv"),
                sep = ",",
                row.names = FALSE)
    print(z)
}

sapply(somelist, csvout)

That is the closest I get, and instead, the files are named what is printed for z:

[1] "X[[1L]]"
[1] "X[[2L]]"
[1] "X[[3L]]"
       a1        a2        a3 
"X[[1L]]" "X[[2L]]" "X[[3L]]" 

In searching the documentation for an answer, I think I'm on the right track here in ?sapply, but I've been unable to connect the dots:

For historical reasons, the calls created by lapply are unevaluated, and code has been written (e.g., bquote) that relies on this. This means that the recorded call is always of the form FUN(X[[i]], ...), with i replaced by the current (integer or double) index

Update

I can use a for loop using syntax similar to C programming...

for (i in 1:length(somelist)) {
    write.table(i, file = paste0("~/somefolder/",
                                 names(somelist)[i],
                                 ".csv"),
                sep = ",",
                row.names = FALSE)
}

But I'm trying to code more natively in R and I'm aware that the apply family, or at least using a vectorized for loop (i.e., for (all in somelist) { instead of for (i in 1:length(somelist)) {) is preferable for efficiency and proper coding etiquette.

Upvotes: 1

Views: 101

Answers (2)

Lev Kuznetsov
Lev Kuznetsov

Reputation: 3728

You can use apply in similar fashion like apply(1:length,function(i){})

Upvotes: 1

Juergen
Juergen

Reputation: 352

This is really, really, really dirty, but I think it works as you described. Of course for more than nine data.frames it needs adjustment in the substitutes part.

csvout <- function (y, csvnames) {
  write.table(y, file = paste0("test",
                                   csvnames[as.numeric(substr(deparse(substitute(y)),4,4))],
                               ".csv"),
              sep = ",",
              row.names = FALSE)
}

sapply(somelist, FUN=csvout, names(somelist))

I suppose you know that, but if you implemented a FOR-loop instead of sapply this would be much easier because you could directly reference the data.frame names with the names function.

Edit: This is the FOR-loop solution which works no matter how many data.frames you've got:

csvout <- function (y) {
  for (i in 1:length(y)){
    write.table(y[i], file = paste0("test",
                                 names(y)[i],
                                 ".csv"),
                sep = ",",
                row.names = FALSE)  
  }  
}

csvout(somelist)

Upvotes: 1

Related Questions