Coercion function within another function not operating properly

Hi everyone,

I am working on developing a R package that needs to coerce vectors, factors, data.frame, tibbles, data.tables, and list into a matrix of character values. For the coercion, I have created a function called char_matrix and returns a matrix of character values, where the column names of the matrix should be the original object or the columns of the original object. You can how I programmed this below. When I test the function using a vector of values only, a matrix is returned with the appropriate column name. However, when I put char_matrix within another function like main_fun, which is listed below, the returned character matrix has a column name of the parameter name and not the R object name.

Would someone be able to assist in adjusting char_matrix, so the appropriate R object name is returned as a column name when char_matrix is used within another function?

I have provided some examples below demonstrating the issue I am having. Thank you for the help!

Erik

# Create functions ####

## char_matrix ####
char_matrix <- function(x = x) {
  # Helper: Null-coalescing operator
  `%||%` <- function(a, b) {
    if (!is.null(x = a)) a else b
  }

  # Capture variable name as string for fallback column name ####
  var_name <- deparse(expr = substitute(expr = x))
  var_name <- gsub(
    x = var_name,
    pattern = ".*\\$",
    replacement = "",
    perl = FALSE
  )

  # Handle factor or character vector ####
  if (is.factor(x = x)) {
    x <- as.character(x = x)
  }

  # Simple vector to single-column character matrix ####
  if (is.atomic(x = x) && is.vector(x = x)) {
    out <- matrix(data = as.character(x = x), ncol = 1)
    colnames(x = out) <- var_name
    return(out)
  }

  # List input: handle unequal-length elements with padding ####
  if (
    is.list(x = x) && !inherits(x = x, what = c("data.frame", "data.table"))
  ) {
    # Creating padded character list ####
    max_len <- max(sapply(X = x, FUN = length))
    padded <- lapply(
      X = x,
      FUN = function(xx) {
        col_char <- as.character(x = xx)
        length(x = col_char) <- max_len # pads with NA automatically
        return(col_char)
      }
    )

    # Creating character matrix ####
    out <- do.call(what = "cbind", args = padded)
    colnames(x = out) <- names(x = x) %||% paste0("V", seq_along(padded))
    return(out)
  }

  # data.frame, data.table, or tibble ####
  if (inherits(x = x, what = c("data.frame", "data.table"))) {
    out <- as.matrix(
      x = data.frame(lapply(x, as.character), stringsAsFactors = FALSE)
    )
    colnames(x = out) <- colnames(x = x)
    return(out)
  }

  # Matrix input ####
  if (is.matrix(x = x)) {
    out <- apply(X = x, MARGIN = c(1, 2), FUN = as.character)
    colnames(x = out) <- colnames(x = x)
    return(out)
  }

  # Throwing an error if coercion fails ####
  stop(
    paste0(
      "x must be a vector, matrix, data.frame, data.table, tibble, factor,",
      " or list."
    )
  )
}


## Main function ####
main_fun <- function(y) {
  if (!inherits(x = y, what = "matrix")) {
    tmp <- try(expr = y <- char_matrix(x = y), silent = TRUE)
    if (inherits(x = tmp, what = "try-error")) {
      stop(
        paste0(
          "y must be a vector, matrix, data.frame, data.table, tibble, factor,",
          " or list."
        )
      )
    }
  }
  return(y)
}

# Generate data ####
z <- sample(x = letters[1:3], size = 100, replace = TRUE)

# Show char_matrix working outside of main function ####
char_working <- char_matrix(x = z)
colnames(char_working)

# Show char_matrix not working within main function ####
char_not_working <- main_fun(y = z)
colnames(char_not_working)

I'd advise against using non-standard evaluation like this and recommend you to read https://adv-r.hadley.nz/index.html.

The reason why it's not working is because substitute will look for the unevaluated expression in the current environment by default (char_matrix() here). If you want to get an expression in a different environment, you'll have to pass the desired environment to the function yourself. Besides, you're looking for an expression called x but the parameter in main_fun() is called y.

It is interesting to also note the impact of permanently declaring the only argument in the function x=x. I think that your function may not recognise external arguments being used.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.