Skip to content
Please note that GitHub no longer supports your web browser.

We recommend upgrading to the latest Google Chrome or Firefox.

Learn more
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Write a list of data.frames to .csv files #207

Closed
billdenney opened this issue Jun 22, 2019 · 3 comments
Closed

Feature Request: Write a list of data.frames to .csv files #207

billdenney opened this issue Jun 22, 2019 · 3 comments
Labels
Milestone

Comments

@billdenney
Copy link
Contributor

@billdenney billdenney commented Jun 22, 2019

I have a feature request to allow writing a list of data.frames as many .csv files.

The interface I'm thinking of could be:

export(x=list_of_data_frames, file="file%s.csv", ...)

And, because I needed it for a project today, I wrote the below code which would support the above (the code below worked for my needs today, but it is not fully tested):

#' Write a list of data.frames to multiple .csv files.
#'
#' @details The \code{path} may be one of three path specifications:
#' \itemize{
#'   \item{A character vector the same length as \code{x} in which case the
#'   filenames are specified as that character vector.}
#'   \item{A character scalar with a single "%%s" indicating where the name of
#'   \code{x} should be inserted.  (Note, \code{sprintf()} is not used to
#'   generate the output filename.)}
#'   \item{A character scalar where the name of \code{x} will be inserted before
#'   the file extension.}
#' }
#' 
#' Names of \code{x} must be unique, or \code{x} must not have a name.  If
#' \code{x} has no names, then integers with left-padded zeros are used.
#'
#' @param x A list of data.frames
#' @param path The filename specification (see the Details section)
#' @return The list of files created (invisibly)
#' @examples
#' \dontrun{
#' example_data <- list(A=data.frame(A=1), B=data.frame(B=1))
#' write_csv_list(example_data, file.path(tempdir(), "test-%s.csv"))
#' }
#' @export
write_csv_list <- function(x, path, ...) {
  if (!is.character(path)) {
    stop("`path` must be a character scalar or vector.")
  }
  if (is.data.frame(x)) {
    stop("`x` must be a list of data.frames, not a data.frame.")
  } else if (!is.list(x)) {
    stop("`x` must be a list of data.frames.")
  } else if (!all(sapply(X=x, FUN=is.data.frame))) {
    stop("`x` must be a list of data.frames, not a list including any other object classes.")
  }
  x_names <-
    if (is.null(names(x))) {
      gsub(
        pattern=" ",
        replacement="0",
        x=format(seq_along(x), justify="right"),
        fixed=TRUE
      )
    } else {
      names(x)
    }
  if (any(x_names %in% "")) {
    stop("All or none of the elements of `x` must be named, empty names are not allowed.")
  } else if (any(duplicated(x_names))) {
    stop("All names of `x` must be unique.")
  }
  find_percent_s <- strsplit(path[1], split="%s", fixed=TRUE)[[1]]
  paths <-
    if (length(path) == length(x)) {
      if (any(duplicated(path))) {
        stop("All values of `path` must all be unique.")
      }
      path
    } else if (length(path) != 1) {
      stop("`path` must either be a single character string or a vector the same length as `x`.")
    } else if (length(find_percent_s) > 2) {
      stop("`path` may only contain a single '%s'.")
    } else if (length(find_percent_s) == 2) {
      paste0(find_percent_s[1], x_names, find_percent_s[2])
    } else if (length(find_percent_s) == 1) {
      message(
        "When giving a single character string for `path`, it is recommended ",
        "to insert '%s' where the names of `x` should be inserted into the ",
        "path name.  The name of `x` will be inserted before the file ",
        "extension."
      )
      file_ext <- rio::get_ext(path)
      tmp_path <- gsub(pattern=paste0(".", file_ext, "$"), replacement="", x=path)
      paste0(tmp_path, x_names, ".", file_ext)
    }
  for (idx in seq_along(x)) {
    write_csv(x=x[[idx]], path=paths[[idx]], ...)
  }
  invisible(paths)
}

If interested, I'm happy to make it into a PR.

@leeper leeper added the enhancement label Jun 26, 2019
@leeper

This comment has been minimized.

Copy link
Owner

@leeper leeper commented Jun 26, 2019

Thanks - give me some time to think about how this should work.

@leeper

This comment has been minimized.

Copy link
Owner

@leeper leeper commented Dec 20, 2019

Implementing a variant of this now as a format-agnostic function: export_list().

@leeper leeper added this to the v0.6 milestone Dec 20, 2019
@leeper leeper closed this in 3d60c50 Dec 20, 2019
@billdenney

This comment has been minimized.

Copy link
Contributor Author

@billdenney billdenney commented Dec 20, 2019

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.