lowndrul
lowndrul

Reputation: 3815

Writing functions to handle multiple data types in R/Splus?

I would like to write a function that handles multiple data types. Below is an example that works but seems clunky. Is there a standard (or better) way of doing this?

(It's times like this I miss Matlab where everything is one type :>)

myfunc = function(x) {
  # does some stuff to x and returns a value
  # at some point the function will need to find out the number of elements
  # at some point the function will need to access an element of x.
  #
  # args: 
  #   x: a column of data taking on many possible types
  #      e.g., vector, matrix, data.frame, timeSeries, list
  x.vec <- as.vector(as.matrix(as.data.frame(x)))
  n <- length(x.vec)
  ret <- x.vec[n/3]  # this line only for concreteness 
  return(ret)
}

Upvotes: 2

Views: 244

Answers (3)

Ari B. Friedman
Ari B. Friedman

Reputation: 72731

Use S3 methods. A quick example to get you started:

myfunc <- function(x) {
    UseMethod("myfunc",x)
}
myfunc.data.frame <- function(x) {
    x.vec <- as.vector(as.matrix(x))
    myfunc(x.vec)
}
myfunc.numeric <- function(x) {
    n <- length(x)
    ret <- x[n/3]
    return(ret)
}
myfunc.default <- function(x) {
    stop("myfunc not defined for class",class(x),"\n")
}

Two notes:

  1. The ... syntax passes any additional arguments on to functions. If you're extending an existing S3 method (e.g. writing something like summary.myobject), then including the ... is a good idea, because you can pass along arguments conventionally given to the canonical function.

print.myclass <- function(x,...) { print(x$keyData,...) }

  1. You can call functions from other functions and keep things nice and parsimonious.

Upvotes: 6

Gavin Simpson
Gavin Simpson

Reputation: 174788

Hmm, your documentation for the function is

# args: 
#   x: a column of data taking on many possible types
#      e.g., vector, matrix, data.frame, timeSeries, list

and if one supplies an object as you claim is require, isn't it already a vector and not a matrix or a data frame, hence obviating the need for separate methods/specific handling?

> dat <- data.frame(A = 1:10, B = runif(10))
> class(dat[,1])
[1] "integer"
> is.vector(dat[,1])
[1] TRUE
> is.vector(dat$A)
[1] TRUE
> is.numeric(dat$A)
[1] TRUE
> is.data.frame(dat$A)
[1] FALSE

I would:

myfunc <- function(x) {
  # args: 
  #   x: a column of data taking on many possible types
  #      e.g., vector, matrix, data.frame, timeSeries, list
  n <- length(x)
  ret <- x[n/3]  # this line only for concreteness 
  return(ret)
}

> myfunc(dat[,1])
[1] 3

Now, if you want to handle different types of objects and extract a column, then S3 methods would be a way to go. Perhaps your example is over simplified for actual use? Anyway, S3 methods would be something like:

myfunc <- function(x, ...)
    UseMethod("myfunc", x)

myfunc.matrix <- function(x, j = 1, ...) {
    x <- x[, j]
    myfunc.default(x, ...)
}

myfunc.data.frame <- function(x, j = 1, ...) {
    x <- data.matrix(x)
    myfunc.matrix(x, j, ...)
}

myfunc.default <- function(x, ...) {
    n <- length(x)
    x[n/3]
}

Giving:

> myfunc(dat)
[1] 3
> myfunc(data.matrix(dat))
[1] 3
> myfunc(data.matrix(dat), j = 2)
[1] 0.2789631
> myfunc(dat[,2])
[1] 0.2789631

Upvotes: 3

please delete me
please delete me

Reputation:

You probably should try to use an S3 method for writing a function that will handle multiple datatypes.
A good reference is here: http://www.biostat.jhsph.edu/~rpeng/biostat776/classes-methods.pdf

Upvotes: 1

Related Questions