Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a c() function for custom S3 class in R

Tags:

r

r-s3

I'm writing an S3 class in R that is just an integer with some attributes attached to it. If x1 and x2 are objects of this class (call it "myclass"), then I would like c(x1, x2) to return a vector of myclass objects with the original class definition and attributes intact. However, the documented behavior of c() is to remove attributes, so it would seem that I need to write my own c.myclass() method. My question is, how can I do this?

An example of the problem:

myclass <- function(x, n) structure(x, class="myclass", n=n)
x1 <- myclass(1, 5)
x2 <- myclass(2, 6)
c(x1, x2)
[1] 1 2

Here the result is just a vector of items of class numeric, and the original n attribute is gone.

Looking at the code for various packages, I sometimes see code like the following, in which we need to preserve the class attribute but nothing else:

c.myclass <- function(..., recursive = F) {
    structure(c(unlist(lapply(list(...), unclass))), class="myclass")
}

Unfortunately I also cannot get this to work. The result of calling c.myclass(x1, x2) is a vector where the vector itself has class "myclass" but where each item in the vector has class numeric; I really want each item in the vector to have class "myclass". In practice I will also need to upgrade this method to preserve other attributes as well (like the attribute "n" in myclass).

like image 366
Abiel Avatar asked Nov 22 '10 00:11

Abiel


People also ask

What is S3 class in R?

An S3 class is the most prevalent and used class in R programming. It is easy to implement this class and most of the predefined classes are of this type. An S3 object is basically a list with its class attributes assigned some names. And the member variable of the object created is the components of the list.

What is S3 generic function?

S3 implements a style of object oriented programming called generic-function OO. This is different to most programming languages, like Java, C++ and C#, which implement message-passing OO. In message-passing style, messages (methods) are sent to objects and the object determines which function to call.

How do you create a class in R?

The simplest way to create a class in S3 is to create a list, and then assign that list to a new class. In traditional object-oriented languages, you would have well-defined methods and attributes, but R is a bit more fluid. The following code shows the creation of the list: p <- list(id=100, rate = 24.50, score = 250)

What is a constructor function in R?

The constructor function should return an object that is a vector corresponding to r with class equal to growth.


2 Answers

Here is an example that does (I think) what you want via specific methods for c and [:

c.myclass <- function(..., recursive = FALSE) {
    dots <- list(...)
    ns <- sapply(dots, attr, which = "n")
    classes <- rep("myclass", length(dots))
    res <- structure(unlist(dots, recursive = FALSE), class = classes)
    attr(res, "n") <- ns
    res
}

`[.myclass` <- function (x, i) {
    y <- unclass(x)[i]
    ns <- attr(x, "n")[i]
    class(y) <- "myclass"
    attr(y, "n") <- ns
    y
}


myclass <- function(x, n) structure(x, class = "myclass", n = n)
x1 <- myclass(1, 5)
x2 <- myclass(2, 6)
c(x1, x2)
c(x1, x2)[2]

But that is a fudge in that we have to manage handling the setting and subsetting of extra attributes to hold the n. This is really just a numeric vector with an attribute for recording n.

It might be more natural to work with the generic of all vectors, a list. Bit that is more involved and maybe the above is sufficient in your case?

like image 182
Gavin Simpson Avatar answered Oct 04 '22 05:10

Gavin Simpson


This does work, but I assume you conclude that each vector element has class numeric because you're doing something like this:

foo <- c(x1, x2)
class(foo[1])
class(foo[2])

If that's the case and you want extracted elements to retain the myclass attribute, you need to write a subset method "[.myclass" to retain the attributes.

like image 24
Joshua Ulrich Avatar answered Oct 04 '22 05:10

Joshua Ulrich