A S
A S

Reputation: 1235

Avoiding If-Then-Else structure in R

The task I'm facing is to return some rows from a list of matrices. Rows to return can be entered as a number or as "first" and "last". I've coded that like this:

showrow <- function(row) {
  if (class(row) == "numeric") {
    getrow <- function(d) {
      d[row,]
    }
    return(getrow)
  } else {
    if (row =="first") {
      getrow <- function(d) {
        head(d, 1)
      }
      return(getrow)
    } else {
      if (row == "last") {
        getrow <- function(d) {
          tail(d, 1)
        }
        return(getrow)
      } else {
        stop("invalid position")
      }
    }
  }
}

And then it's possible to use it like that:

a <- matrix(rnorm(20), 4)
b <- matrix(rnorm(100), 10)
lst <- list(a, b) ; lst
num <- "last" # Or `num <- "first"`, or `num <- 3`, etc
lapply(lst, function(df) { showrow(num)(df) })

The problem is I think that If structure still looks clumsy... Is there any workaround to avoid it in this particular scenario?


(And, on a side note, is it possible to return NAs if the subscript would be out of bounds, like num <- 11, for example?)

Upvotes: 2

Views: 687

Answers (3)

BrodieG
BrodieG

Reputation: 52637

You greatly simplify your problem if you change your interface to:

show me the last row if you give me anything but a number, or that row otherwise:

showrow <- function(row) {
  if(!is.numeric(row)) return(function(x) tail(x, 1L))
  function(x) tryCatch(x[row, ], error=function(e) NA)
}

Usage examples:

showrow("last")(a)   # Last row
showrow(4)(a)        # 4th row (also last in this case)
showrow(2:3)(a)      # 2nd and 3rd
showrow(20)(a)       # Returns NA

You don't need to have a special token for "first" since 1 works just fine. Then you can do stuff like this. Obviously showrow("first")(mx) would still return the last row, which might be confusing. Really the best thing would be something like:

show me a specific row if I specify it, or the last one if I don't.

That's even easier to implement.

Upvotes: 1

cdeterman
cdeterman

Reputation: 19960

Here is a switch solution.

showrow <- function(row) {
  switch(class(row),
         numeric = function(d) {
           d[row,]
         },
         character = switch(row,
                            first = function(d){
                              head(d,1)
                            },
                            last = function(d){
                              tail(d,1)
                            },
                            {stop("Invalid position")}),
        {stop("Invalid position")}
  )
}

Upvotes: 1

Marat Talipov
Marat Talipov

Reputation: 13304

Here is one approach:

showrow <- function(row) {
  if (class(row) == "numeric") return(function(d) d[row,])
  f <- list(first=head,last=tail)[[row]]
  if (is.null(f)) stop("invalid position")
  function(d) f(d,1)
}

Upvotes: 1

Related Questions