Reputation: 17537
Does anyone have any experience using Reference Classes as the levels of a factor? This is one step in my goal of adding "foreign-key-like" support to a data.frame
in one of my packages.
I'm ultimately looking to create a data.frame
which can store, as integers, the codes associated with a factor, but the levels of this factor are actually Reference Class objects, rather than the character vectors factors typically use. I've been able to find some information on using S4 objects as levels of a factor, but the techniques don't seem to be working for Reference Classes.
For instance, a simple:
> myClass <- setRefClass("MyClass", fields=list(a="numeric", b="character"))
> myObj <- myClass$new(a=1, b="test")
> factor(myObj)
Error in unique.default(x) : unique() applies only to vectors
> as.character(myObj)
Error in as.vector(x, "character") :
cannot coerce type 'environment' to vector of type 'character'
> as.character.MyClass <- function(x){ x$b }
> as.character(myObj)
[1] "test"
> factor(myObj)
Error in unique.default(x) : unique() applies only to vectors
>
> unique.MyClass <- function (x, incomparables = FALSE, ...) { unique(as.character(x)) }
> factor(myObj)
Error in as.vector(x, mode) : invalid 'mode' argument
> traceback()
2: as.vector(exclude, typeof(x))
1: factor(myObj)
doesn't seem to get anything working. It looks like, at my best, I can get to the line in factor()
which analyzes the exclude
parameter:
exclude <- as.vector(exclude, typeof(x))
at which point everything falls apart, since I'm not allowed to create a vector of type "S4".
Any thoughts on how to solve this or -- even better -- alternative approaches to map an integer to an Reference Class object in a data.frame
-friendly way would be much appreciated!
Edit: In response to @Aaron's question below:
The simple solution here would be to just store integers in the data.frame
and then maintain a separate list/data.frame
responsible for mapping those IDs to some other data (such as Reference Class objects). This would maintain all of the necessary data to accomplish what I need, but would be less elegant, to me, for a couple of reasons:
data.frame
to print the names of the employees, rather than their IDs.data.frame
. In the same way that as.character(myDataFrame$someColumn)
would give me the labels of that column (assuming it's a factor) rather than the underlying integers actually being stored in the data.frame
.Again, I'm very open to alternative solutions to this problem if there's a better way to go about it!
Upvotes: 2
Views: 494
Reputation: 37814
I think this could be done by making a new class, say, myFactor
, with the necessary methods; format
seems to be the one you need for printing in a data frame; you could easily add print
or other methods of your choice. I'm most comfortable with S3 methods, so that's what I've done here.
Here I set up both your reference class and the format
function for the myFactor
class.
myClass <- setRefClass("MyClass", fields=list(a="numeric", b="character"))
format.myFactor <- function(obj, ...) {
n <- sapply(levels(obj), function(x) x[["b"]])
n[obj]
}
Here I make two new reference objects, and use them as levels of my new myFactor
object.
myObj <- myClass$new(a=1, b="test")
myObj2 <- myClass$new(a=4, b="testagain")
foo <- structure(c(2,1,2), levels=c(myObj, myObj2), class=c("myFactor","numeric"))
d <- data.frame(x=foo)
It then prints nicely.
> d
x
1 testagain
2 test
3 testagain
Upvotes: 1