2

I have 168 files saved in a list and I'm trying to save them to my folder using a for loop.
I need to name the file as provided below, but what my code does now is save 168 files with different names, but it saves the same file 168 times instead of looping through and saving each file in the list with a separate name.
Any way to do this?

strings_label = c('a', 'approxequal', 'b', 'c', 'd', 'e', 'equal',
                  'f', 'five', 'four', 'g', 'greater', 'greaterequal',
                  'less', 'lessqual', 'notequal', 'one', 'seven',
                  'six', 'three', 'two')
strings_number = c('01', '02', '03', '04', '05', '06', '07', '08')
suffix = '40264464'

for(p in 1:length(myelement))
  for(this_label in strings_label)
  {
    for(this_number in strings_number)
    {
      
      write.csv(myelement[[p]],
                paste0("/Users/jwolo/Documents/section_images/",
                paste(this_label, this_number, suffix, sep = "_"), ".csv"),
                row.names = TRUE)
    }
  }
}

Any help would be really appreciated.

Dave2e
  • 22,192
  • 18
  • 42
  • 50
  • 1
    Your code look fine despite a missing `{` for the first loop. May you try print out the `file.path` arguments part just to verify if it is what you want it suppose to be? – Sinh Nguyen Feb 22 '21 at 22:21

2 Answers2

3

The current code is looping through all of the filenames for each increment of p. Thus saving the last data frame to all of the files.
One way to handle that is to increment p within the inside loop.

p<-1
for(this_label in strings_label){
      for(this_number in strings_number)
      {
         write.csv(myelement[[p]],
                   paste0("/Users/jwolo/Documents/section_images/",
                          paste(this_label, this_number, suffix, sep = "_"), ".csv"),
                   row.names = TRUE)
         p<- p +1
      }
}
Dave2e
  • 22,192
  • 18
  • 42
  • 50
3

Let me suggest some style improvements. These will help you not only write arguably nicer code but also help you write the code in the first place as each problem will be disassembled into smaller easily solvable problems.

Note that some of these might be little advanced solutions.

First, define a function that will generate file name:

make_filename = function(label, number){
  # these can be easily turned into parameters
  suffix = "40264464"
  dir = "/Users/jwolo/Documents/section_images/"

  # doing this, putting it all on a single line or using pipe %>%
  # is just matter of style
  filename = paste(label, number, suffix, sep="_")
  filename = paste0(filename, ".csv")
  filename = file.path(dir, filename)

  filename
}

To get all combinations of two elements, consider expand.grid. This can be used together with mapply to make names:

combinations = expand.grid("label"=string_label, "number"=string_number)
filenames = mapply(make_filename, combinations$label, combinations$number)

With another mapply or if you make another function, all can be done in a single mapply call:

save_element = function(element, label, number){
  filename = make_filename(label, number)
  write.csv(element, filename,row.names=TRUE)
  }

combinations = expand.grid("label"=string_label, "number"=string_number)
mapply(save_element, myelement, combinations$label, combinations$number)

By wrapping the logic of individual steps into self-contained functions, the result is more readable, less bug-prone, code.

Explanation:

All the magic is in two functions, expand.grid which produce a combination of input vectors into a data.frame:

expand.grid(c("a","b"), c(1,2))
#  Var1 Var2
#1    a    1
#2    b    1
#3    a    2
#4    b    2

By specifying the names of the input vectors, the columns are then named so we can point at them instead of using res[,1] and res[,2] which is less readable compared to res$letters and res$numbers.

The second magic is mapply, which is just a different name for Map function that you might know from different programming languages (such as Python).

While it looks terrifying, mapply is really simple. It just calls functions with first element of its inputs, then second element and so on. It is essentially:

for(i in 1:n)
   fun(input1[i], input2[i], ..., inputk[i])

Just a bit smarter.

Colombo
  • 428
  • 3
  • 12
  • 2
    Interesting stuff, I'm really new to R coding so I've been using really basic techniques, but I'll definitely try out the things you suggested! Thanks so much – Jakub Woloszyn Feb 23 '21 at 01:03