R/utils-mappers.R

Defines functions bind_rows map2_df map_df map2_int map_int map2_dbl map_dbl map2_lgl map_lgl map2_chr map_chr map2 map

# NOTE these aren't 100% equivalent to the purrr mappers but cover very common use-cases
#
# NOTE formula function (e.g. ~{}) are 100% supported

map <- function(.x, .f, ...) {

  if (inherits(.f, "formula")) {
    .body <- dimnames(attr(terms(.f), "factors"))[[1]]
    .f <- function(.x, . = .x) {}
    body(.f) <- as.expression(parse(text=.body))
  }

  if (inherits(.f, "function")) {
    lapply(.x, .f, ...)
  } else if (is.numeric(.f)) {
    lapply(.x, `[`, .f)
  }

}

map2 <- function(.x, .y, .f, ...) {

  if (inherits(.f, "formula")) {
    .body <- dimnames(attr(terms(.f), "factors"))[[1]]
    .f <- function(.x, .y, . = .x) {}
    body(.f) <- as.expression(parse(text=.body))
  }

  if (inherits(.f, "function")) {
    mapply(.f, .x, .y, ..., SIMPLIFY=FALSE, USE.NAMES=FALSE)
  }

}

map_chr <- function(.x, .f, ...) {
  as.character(unlist(map(.x, .f, ...), use.names = FALSE))
}

map2_chr <- function(.x, .y, .f, ...) {
  as.character(unlist(map2(.x, .y, .f, ...), use.names = FALSE))
}

map_lgl <- function(.x, .f, ...) {
  as.logical(unlist(map(.x, .f, ...), use.names = FALSE))
}

map2_lgl <- function(.x, .y, .f, ...) {
  as.logical(unlist(map2(.x, .y, .f, ...), use.names = FALSE))
}

map_dbl <- function(.x, .f, ...) {
  as.double(unlist(map(.x, .f, ...), use.names = FALSE))
}

map2_dbl <- function(.x, .y, .f, ...) {
  as.double(unlist(map2(.x, .y, .f, ...), use.names = FALSE))
}

map_int <- function(.x, .f, ...) {
  as.integer(unlist(map(.x, .f, ...), use.names = FALSE))
}

map2_int <- function(.x, .y, .f, ...) {
  as.integer(unlist(map2(.x, .y, .f, ...), use.names = FALSE))
}


map_df <- function(.x, .f, ..., .id=NULL) {

  res <- map(.x, .f, ...)
  out <- bind_rows(res, .id=.id)
  out

}

map2_df <- function(.x, .y, .f, ..., .id=NULL) {

  res <- map(.x, .y, .f, ...)
  out <- bind_rows(res, .id = .id)
  out

}

# this has limitations and is more like 75% of dplyr::bind_rows()
# this is also orders of magnitude slower than dplyr::bind_rows()
bind_rows <- function(..., .id = NULL) {

  res <- list(...)

  if (length(res) == 1) res <- res[[1]]

  cols <- unique(unlist(lapply(res, names), use.names = FALSE))

  if (!is.null(.id)) {
    inthere <- cols[.id %in% cols]
    if (length(inthere) > 0) {
      .id <- make.unique(c(inthere, .id))[2]
    }
  }

  id_vals <- if (is.null(names(res))) 1:length(res) else names(res)

  saf <- default.stringsAsFactors()
  options(stringsAsFactors = FALSE)
  on.exit(options(stringsAsFactors = saf))

  idx <- 1
  do.call(
    rbind.data.frame,
    lapply(res, function(.x) {
      x_names <- names(.x)
      moar_names <- setdiff(cols, x_names)
      if (length(moar_names) > 0) {
        for (i in 1:length(moar_names)) {
          .x[[moar_names[i]]] <- rep(NA, length(.x[[1]]))
        }
      }
      if (!is.null(.id)) {
        .x[[.id]] <- id_vals[idx]
        idx <<- idx + 1
      }
      .x
    })
  ) -> out

  rownames(out) <- NULL

  class(out) <- c("tbl_df", "tbl", "data.frame")

  out

}
hrbrmstr/gdns documentation built on May 17, 2020, 3:37 a.m.