Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extend as.list in a canonical way to S4 objects

Tags:

r

r-s4

I am having some trouble converting my S4 object back into a list. Take for example, the following nested S4 classes:

setClass("nssItem", 
         representation(value = "numeric", text = "character", prefix = "character", type = "character"),
         prototype(value = as.numeric(NA), text = as.character(NA), prefix = as.character(NA), type = as.character(NA))

         ) 

setClass("geckoNss", representation(absolute = "character", item = "nssItem"))

An object of geckoNss class contains objects of nssItem class. Conceptually this seems like a list-like structure which allows for nesting.

Yet,

> temp <- new("nssItem")
> as.list(temp)
Error in as.list.default(temp) : 
  no method for coercing this S4 class to a vector

I understand this error, that is, I have not actually defined what as.list means or how it applies with respect to the nssItem class. Nonetheless, this seems like a very natural operation. How would I extend the definition of as.list to all new classes I define?

like image 568
Alex Avatar asked Feb 01 '26 23:02

Alex


1 Answers

This is a second, more general solution. It uses a superclass from which you derive all user-defined classes. Descriptions are in the # comments.

#this is an "empty" superclass that characterises all user-defined classes
setClass("user_defined_class")

#we create an as.list method for this new superclass (this time an S4 method)
setMethod("as.list",signature(x="user_defined_class"),function(x) {
  mapply(function(y) {
    #apply as.list if the slot is again an user-defined object
    #therefore, as.list gets applied recursively
    if (inherits(slot(x,y),"user_defined_class")) {
      as.list(slot(x,y))
    } else {
      #otherwise just return the slot
      slot(x,y)
    }
  },
slotNames(class(x)),
SIMPLIFY=FALSE)
})

setClass("nssItem", 
     representation(value = "numeric",
                    text = "character",
                    prefix = "character",
                    type = "character"),
     prototype(value = as.numeric(NA),
               text = as.character(NA),
               prefix = as.character(NA),
               type = as.character(NA)),
     #note the contains argument that flags the nssItem class as user-defined
     contains="user_defined_class")

setClass("geckoNss",
         representation(absolute = "character", item = "nssItem"),
         #the same for the geckoNss class
         contains="user_defined_class")

Now create one object for each class

temp <- new("nssItem")
tempGecko<-new("geckoNss")

Coerce temp to list

as.list(temp)
#$value
#[1] NA
#
#$text
#[1] NA
#
#$prefix
#[1] NA
#
#$type
#[1] NA

And the tempGecko object

as.list(tempGecko)
#$absolute
#character(0)
#
#$item
#$item$value
#[1] NA
#
#$item$text
#[1] NA
#
#$item$prefix
#[1] NA
#
#$item$type
#[1] NA
like image 182
cryo111 Avatar answered Feb 03 '26 11:02

cryo111