0

I intend to mount a list of dataframe then use a loop structure to write each in a .csv file. Something like that:

for (i in myDataFramelist) 
  write.csv( ...)
alistaire
  • 38,696
  • 4
  • 60
  • 94
  • Use `lapply`, which is designed for iterating over a list. If you need a multivariate version that iterates in parallel (say over your list and a vector of names), see `?Map`. [purrr](https://purrr.tidyverse.org/) provides versions of these functions, if you like. – alistaire Jun 16 '18 at 16:28
  • how can I use write.csv function nested with lapply? – Bruno Lopes Jun 16 '18 at 16:47
  • Since you'll usually need a vector of names, too, it usually looks like `Map(function(df, filename) write.csv(df, filename), myDataFrameList, filenames)`. In this case you don't even really need the anonymous function, so you could reduce it to `Map(write.csv, myDataFrameList, filenames)` – alistaire Jun 16 '18 at 16:52
  • Map sounds a good option! Thanks! – Bruno Lopes Jun 17 '18 at 00:21

3 Answers3

2

Since you're working with a list and mention dplyr, purrr's walk functions are well suited. Unlike map, walk expects to apply a function to each element of a list without returning or printing to the console, so it's a good choice for saving files. iwalk takes both the list elements and the list elements' names, which is useful for creating file names. Here are a few ways to do it. For dummy data, I split the mpg data frame and took the first 3 elements.

library(tidyverse)

df_list <- mpg %>% split(.$manufacturer) %>% `[`(1:3)

# makes files mpg_audi.csv, etc
iwalk(df_list, function(df, name) {
  write_csv(df, sprintf("mpg_%s.csv", name))
})

purrr functions let you use dot notation as a shorthand—for something more complex than this, I'd prefer writing out the function as above, just to be clear about what's going on, but in this case .x is shorthand for each data frame and .y is shorthand for each data frame's name.

# makes files mpg_audi_dot_notation.csv, etc
iwalk(df_list, ~write_csv(.x, sprintf("mpg_%s_dot_notation.csv", .y)))

If your list doesn't have names, you can instead use walk2, which takes two arguments, and use the location in the list as the second argument.

names(df_list) <- NULL

# makes files mpg_1.csv, etc
walk2(df_list, 1:length(df_list), ~write_csv(.x, sprintf("mpg_%s.csv", .y)))

Created on 2018-06-16 by the reprex package (v0.2.0).

camille
  • 13,812
  • 10
  • 29
  • 45
1

R is a highly vectorized language, so you usually don't need to use for loops :

lapply(Filter(function(x) is.data.frame(get(x)), ls()), 
       function(x) write.csv(get(x), paste0(x, ".csv")))

Explanation:

  • You use lapply as you're going to apply a function to a list
  • ls gives all objects in envirnoment
  • is.data.frame will return TRUE if the object is a data.frame
  • Filter will select wich are TRUE
  • You already know what write.csv does, you pass get(x) as the object to be saved, and make a name with the object's name
PavoDive
  • 5,293
  • 20
  • 50
  • It's better to use [a list of data frames](https://stackoverflow.com/a/24376207/4497050) like the OP already has than `get`. – alistaire Jun 16 '18 at 16:55
  • @alistaire please help me learn a bit more about this... From the title ("how can I create a list of data frames in memory) I understand that the OP doesn't really have a list, and therefore I used the `get` and `ls` to build it. But provided that there's such a list, why is it better to use the list than to making it with `get`? is it time only?. Thanks, I learn a lot from you guys! – PavoDive Jun 16 '18 at 17:05
  • In that case the question isn't that important, but Gregor's answer is excellent and gets to your question. To summarize, there are 2 main benefits: 1. It scales better, so you end up with one list instead of thousands of data frames in your global environment, and can name them how you like without worrying about how to access them. 2. R has lots of excellent ways to iterate over and manipulate lists. There are great tools for coercing a list of data frames to a single one, too, e.g. `dplyr::bind_rows` and `data.table::rbindlist`. – alistaire Jun 16 '18 at 17:22
0

Even if it might not be the best way of doing it, I guess this example can make you understand a way through:

mat1<- matrix(1:9,3,3)
mat2<- matrix(1:16,4,4)
mylist <- list(mat1,mat2)

for( i in 1:length(mylist)){
  name<- paste0("matrix",i) ## Write the name you want
  write.csv(mylist[[i]], name) # Add the location where you want to store the file if so
}

Cheers !

Carles Sans Fuentes
  • 2,192
  • 8
  • 22