Question

How do I create an S4 class which has arrays as slots? Below, I have an example class. I'd like to be able to construct in such a way that I get two "person" elements, each of which has appropriate array members.

The code below gives me the following error: "Error in validObject(.Object) : invalid class “person” object: invalid object for slot "children" in class "person": got class "character", should be or extend class "array"

setClass("person", representation(name="character", age="numeric", children = "array"))

setMethod(
  f = "[",
  signature="person",
  definition=function(x,i,j,...,drop=TRUE){ 
    initialize(x, name=x@name[i], age = x@age[i], children = x@children[i])
  }
)

setMethod(f = "length", signature = "person", definition = function(x){
  length(x@name)
})

setMethod(f = "dim", signature = "person", definition = function(x){
  length(x@name)
})

kids1 = as.array(c("Bob", "Joe", "Mary"))

person = new("person", name="John", age=40, children = kids1)

person@children[2]

kids2 = as.array(c("Steve", "Beth", "Kim"))

people = new("person", name=c("John", "Fred"), age=c(40, 20), children = as.array(c(kids1, kids2), dim = 2))

people[1]@age
people[2]@children[1]
Was it helpful?

Solution

You probably don't want @children to be an array. With a dim attribute of length 1, it's essentially the same as a vector, and you lose the ability to distinguish different people's children. Consider making this slot a list instead.

setClass("person",
    representation(name="character", age="numeric", children = "list"))

person = new("person", name="John", age=40, children = list(kids1))
person@children

people = new("person", name=c("John", "Fred"), age=c(40, 20),
             children = list(kids1, kids2))
people[1]

OTHER TIPS

Add drop=FALSE to your subset of the children slot; this is a consequence of standard R rules for array subsetting

setMethod(
  f = "[",
  signature="person",
  definition=function(x,i,j,...,drop=TRUE){ 
    initialize(x, name=x@name[i], age = x@age[i], 
      children = x@children[i,drop=FALSE])
  }
)

Also I'm not sure that your as.array() is doing what you think? The dim argument is being ignored.

Hong's answer works. I did need to add a list wrapper in the "[" subset function. Once that's done, everything works fine.

kids1 = as.array(c("Bob", "Joe"))
kids2 = as.array(c("Steve", "Beth", "Kim"))

setClass("person", representation(name="character", age="numeric", children = "list"))

setMethod(
  f = "[",
  signature="person",
  definition=function(x,i,j,...,drop=TRUE){ 
    initialize(x, name=x@name[i], age = x@age[i], children = list(x@children[i]))
  }
)

people = new("person", name=c("John", "Fred"), age=c(40, 20), children = list(kids1, kids2))

people[1]@name
people[1]@age
people[1]@children

people[2]@name
people[2]@age
people[2]@children
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top