I would like to be able to apply the "subset" (bracket) [
method on a S4 object let's call it foo
in such a way that when it is called setMethod("[", 'foo', ...
it will apply the [
operator on the data.table it holds in a specific slot.
Example:
foo <- setClass("foo", slots = c(myDT = "data.table"),
prototype = prototype( myDT = NULL ))
# quickly make a foo class with a DT in the myDT slot
myfoo <- new("foo", myDT = data.table(x=rep(c("b","a","c"),each=3), y=c(1,3,6), v=1:9))
# sneak peek
myfoo
An object of class "foo"
Slot "myDT":
x y v
1: b 1 1
2: b 3 2
3: b 6 3
4: a 1 4
5: a 3 5
6: a 6 6
7: c 1 7
8: c 3 8
9: c 6 9
The tricky part
# I want to be able to do eg
myfoo[1:3, 2:3]
y v
1: 1 1
2: 3 2
3: 6 3
and have it give me the same result as if doing:
myfoo@myDT[1:3, 2:3]
y v
1: 1 1
2: 3 2
3: 6 3
So far (I am guessing) it will/should be something along the lines of
setMethod(f = "[", signature = signature(x = "foo"),
definition = function(x, ...) {
`[`([email protected], ...)
# OR maybe
# x <- x@myDT
# callNextMethod(x, ...)
}
)
But whatever I call myfoo[i,j]
with it wll always just return the whole data.table.
Any ideas if this can be accomplished? So far I am stuck usually on errors about j
not fitting the bill.
And I would like to avoid having to fully implement some form of shadow-indexing for this slot if I can somehow "recycle" what is available in data.table
already;
of course also with the added benefit of the other data.table
functions maybe also being applicable this way?
But for a beginning "passing on" indices would be a good start.
PS: If you wonder why not just do myfoo@myDT
- the real life foo
class has multiple slots of which only one (the data.table
one) is "worthy" to be indexed and so I want to "shortcut" that methods application a bit.
CodePudding user response:
I found a way to achieve above task (by borrowing ideas from here).
Feels a bit "hacky" but maybe someone will still jump in (later) with a more elegant solution.
fooDT <- setClass("fooDT", contains = "data.table")
setGeneric("as.fooDT", function(x) standardGeneric("as.fooDT"))
setMethod("as.fooDT", signature = "foo",
function(x) new("fooDT", [email protected])
)
setMethod(f = "[", signature = signature(x = "foo"),
definition = function(x, ...) {
x <- as.fooDT(x)
callGeneric()
}
)
CodePudding user response:
If you created the foo
class, is it "a data table with a few things tacked on"? If so, then consider redefining your class to extend the data class:
setClass("foo",slots=list(
##other slots besides data table
),extends="data.table") -> foo
Then any method defined for a data table will work for this (use [email protected]
to get at the "data table part" of foo
object x
if you need to).
If not, then you can still define your own method to act on another slot, as follows:
setMethod("[",
signature(x="foo",i="ANY",j="ANY"),
def=function(x,i,j) x@myDT[i,j]
)
the reason this may not have worked before is that you didn't include i
and j
in the method signature. You may also need to define a method for signature x="foo",i="ANY",j="missing"
to cover the case when j
isn't specified at all.