Why does this switch statement (case_else too) not work if I try to forward pipe it?

44 views Asked by At

Why does this work:

 est <- unlist(column) %>%
    sample(i, replace = TRUE) %>%
    matrix(nrow = B, ncol = i) # %>%
  
  est <- switch(param,
           "mean" = rowMeans2(est, na.rm = TRUE),
           "sd" = rowSds(est, na.rm = TRUE),
           stop("Invalid `param` value. Valid values are 'mean' or 'sd.'")
           ) # %>%
  
  est <- mean(est)

But this does not:

  est <- unlist(column) %>%
    sample(i, replace = TRUE) %>%
    matrix(nrow = B, ncol = i) %>%
    switch(
      param,
      "mean" = rowMeans2(., na.rm = TRUE),
      "sd" = rowSds(., na.rm = TRUE),
      stop("Invalid `param` value. Valid values are 'mean' or 'sd.'")
    ) %>%
    mean()

The example using pipes gives the following error:

Error in switch(., param, mean = rowMeans2(., na.rm = TRUE), sd = rowSds(., : EXPR must be a length 1 vector

Also found case_when fails using pipes:

  case_when(
      param == "mean" ~ rowMeans2(na.rm = TRUE),
      param == "sd" ~ rowSds(na.rm = TRUE),
      TRUE ~ (stop("Invalid `param` value. Valid values are 'mean' or 'sd.'"))
    ) %>%
    mean()

With a different error:

Error in case_when(): ! Case 1 (.) must be a two-sided formula, not a double matrix.

Minimal code sample for repro:

# Sample data
set.seed(123)
column <- data.frame(X1 = rnorm(100))

# Parameters
i <- 5
B <- 100
param <- "mean"

# Load matrixStats
library(matrixStats)

# My function
myFunc <- function(i, column, B, param) {
  est <- unlist(column) %>%
    sample(i, replace = TRUE) %>%
    matrix(nrow = B, ncol = i) %>%
    switch(
      param,
      "mean" = rowMeans2(., na.rm = TRUE),
      "sd" = rowSds(., na.rm = TRUE),
      stop("Invalid `param` value. Valid values are 'mean' or 'sd.'")
    ) %>%
    mean()
  
  # Print the result
  print(est)
}

# Call the function for testing
myFunc(i, column, B, param)
1

There are 1 answers

3
PBulls On BEST ANSWER

You are calling switch inside the pipeline, so the previous output will take the place of its first argument EXPR. That's not a scalar, so that's an error, and it's also no longer the param which you intended to use. You can easily get around this by parsing param first, and you also only need to do this once (not for every value in the pipeline):

myFunc <- function(i, column, B, param) {
  ## Parse once, outside pipeline
  paramfunc <- switch(
    param,
    "mean" = \(x) rowMeans2(x, na.rm = TRUE),
    "sd" = \(x) rowSds(x, na.rm = TRUE),
    stop("Invalid `param` value. Valid values are 'mean' or 'sd.'")
  )
  
  ## Insert above into pipeline
  est <- unlist(column) %>%
    sample(i, replace = TRUE) %>%
    matrix(nrow = B, ncol = i) %>%
    paramfunc() %>%
    mean()
  
  # Print the result
  print(est)
}

myFunc(i, column, B, param)
#> 0.5044144