2013-10-12 2 views
2

Пусть у меня есть функция, как это:Может ли объект в R иметь более одного класса?

myf = function(x) { 
res = dostuff(x) 
res # this is a data.frame 
} 

Я хочу сделать что-то особенное res, например, я хочу сделать некоторые общие функции, такие как print.myf, summary.myf, ... , так что я могу идти вперед и дать ему класс:

myf = function(x) { 
res = dostuff(x) 
class(res) = 'myf' 
res 
} 

Но этот способ я больше не могу использовать в качестве data.frame.

+2

Да. В вашей функции перепишите 'class (res) =" myf "' to 'class (res) <- c (" myf ", class (res))'. – A5C1D2H2I1M1N2O1R2T1

ответ

2

Вот пример с rle. Функция rle создает list, но у нее нет класса list, поэтому методы, подобные as.data.frame, не будут работать «из коробки». Таким образом, я изменил последнюю строку, добавив "list" в качестве одного из классов.

x <- c(1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3) 

rle2 <- function (x) 
{ 
    if (!is.vector(x) && !is.list(x)) 
    stop("'x' must be an atomic vector") 
    n <- length(x) 
    if (n == 0L) 
    return(structure(list(lengths = integer(), values = x), 
        class = "rle")) 
    y <- x[-1L] != x[-n] 
    i <- c(which(y | is.na(y)), n) 

    ## THE FOLLOWING IS FROM THE BASE RLE. NOTICE ONLY ONE CLASS... 
    # structure(list(lengths = diff(c(0L, i)), values = x[i]), 
    # class = "rle") 

    structure(list(lengths = diff(c(0L, i)), values = x[i]), 
      class = c("rle", "list")) 
} 

Как вы можете видеть, я просто изменил class. Остальная часть функции одинаков.

rle(x) 
# Run Length Encoding 
# lengths: int [1:3] 4 3 7 
# values : num [1:3] 1 2 3 
data.frame(rle(x)) 
# Error in as.data.frame.default(x[[i]], optional = TRUE, stringsAsFactors = stringsAsFactors) : 
# cannot coerce class ""rle"" to a data.frame 
rle2(x) 
# Run Length Encoding 
# lengths: int [1:3] 4 3 7 
# values : num [1:3] 1 2 3 
data.frame(rle2(x)) 
# lengths values 
# 1  4  1 
# 2  3  2 
# 3  7  3 

Конечно, если мы знаем, что это, мы могли бы также явно указать наши методы, если мы знаем, существует один:

as.data.frame.list(rle(x)) 
# lengths values 
# 1  4  1 
# 2  3  2 
# 3  7  3 
2

Да, мой стандартный (простой) пример

R> now <- Sys.time() 
R> class(now) 
[1] "POSIXct" "POSIXt" 
R> class(as.POSIXlt(now)) 
[1] "POSIXlt" "POSIXt" 
R> 

Это также причина про кончике тестирования с inherits("someClass"), а не испытывать результат class(obj)=="someClass".

Смежные вопросы