I'm experimenting with S3-class
methods and generic functions, but I'm having an issue which I think highlights a misunderstanding in my thinking. Perhaps I'm getting confused with how printing works, or how storing values
and attributes
works internally?
I've tried to google around to no avail, possibly because I'm not too sure what I'm looking for.
library(data.table)
# trivial data
dt <- CJ(letter = c("A", "B", "C"), number = 1:4)
# -- generic functions
coverage <- function (x, ...) {
UseMethod("coverage", x)
}
prettyprint <- function (x, ...) {
UseMethod("prettyprint", x)
}
# coverage method to find % of data.table satisfying an expr
coverage.data.table <- function(dt, subset, desc) {
e <- parse(text = subset) # parse condition to expression
coverage <- dt[eval(e), .N]/dt[, .N] # express coverage as a percent
class(coverage) <- c("coverage", class(coverage)) # set as 'coverage' class
attributes(coverage)[["desc"]] <- desc # carry description for printing
coverage
}
# human readable data.table coverage
prettyprint.coverage <- function(coverage) {
desc <- attributes(coverage)[["desc"]]
paste0(round(coverage*100, 2), "% ", desc)
}
# normal printing
print.coverage <- function(coverage) {
# unsure what to put in here such that I can use
# this value with standard other operations such
# as multiplication
}
coverageB <- coverage(dt, "letter == \"B\"", "of data.table is in B")
> coverageB # prints nothing as expected from empty function
> prettyprint(coverageB)
[1] "33.33% of data.table is in B"
Printing coverageB
without loading print.coverage
gives
> coverageB
[1] 0.3333333
attr(,"class")
[1] "coverage" "numeric"
attr(,"desc")
[1] "of data.table is in B"
where I'd like some way to print just the 0.3333333
.
Help would be much appreciated. Thanks.
(As a side note, I'm sure that eval(parse(...))
statement is not the right way to do things. Any pointers there would be appreciated too.)
I also wasn't sure what to title this - if anyone has any more appropriate suggestion I'm happy to change it.
Here are two better possibilities, the first following your approach (which might be faster due to automatic indexing, but I haven't benchmarked):
coverage.data.table <- function(dt, subset, desc) {
coverage <- dt[eval(substitute(subset)), .N]/dt[, .N] # express coverage as a percent
#coverage <- dt[, mean(eval(substitute(subset)))] # express coverage as a percent
class(coverage) <- c("coverage", class(coverage)) # set as 'coverage' class
attributes(coverage)[["desc"]] <- desc # carry description for printing
coverage
}
Then you call it like this:
coverageB <- coverage(dt, letter == "B", "of data.table is in B")
Here is a print
method that uses c
to remove all attributes (see its documentation):
# normal printing
print.coverage <- function(coverage) {
print.default(c(coverage))
}
coverageB
#[1] 0.3333333
prettyprint(coverageB)
#[1] "33.33% of data.table is in B"
However, I don't understand your comments regarding the print
method. The print
method is in no way connected to multiplication.