Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving S4 objects in a list of list

Tags:

list

r

s4

R is giving the following message error when you want to save an S4 object into a list of list and the element was not already defined previously.

"invalid type/length (S4/0) in vector allocation"

Why is it working with a simple list, but not with a list of list?

See the following code and the potential workarounds. However, I am pretty sure there is a more obvious solution.

# Creation of an S4 object
setClass("student", slots=list(name="character", age="numeric", GPA="numeric"))
s <- new("student",name="John", age=21, GPA=3.5)

# Indexes for the list
index1 <- "A"
index2 <- "a"

# Simple list (All of this works)
l <- list()
l[[index1]] <- s
l[[index1]] <- "character"
l[[index1]] <- 999


# List of list 
l <- list()
l[[index1]][[index2]] <- s          # will give an Error!!
l[[index1]][[index2]] <- "character" # still working
l[[index1]][[index2]] <- 999         # still working


# "Workarounds"
l <- list()
l[[index1]][[index2]] <- rep(999, length(slotNames(s))) #define the element with a length equal to the number of slots in the s4 object
l[[index1]][[index2]] <- s # this works now!


l[[index1]][[index2]] <- list(s) # This works too, but that's not the same result

Any suggestion on why it does not work with a list of list and how I can solve this problem? Thanks

like image 211
Arnaud Avatar asked Mar 25 '19 16:03

Arnaud


1 Answers

So when you do

l <- list()
l[[index1]][[index2]] <- s

the problem is that that l is initialized to be a list so it makes sense to set a new named element with l[[index1]], but R has no idea what's stored at l[[index1]][[index2]]. It could be anything. It could be a function and functions don't know what to do with a named indexing operation. For example

l <- list()
l[[index1]] <- mean
l[[index1]][[index2]] <- "character"

But in your case, when you try to grab a value form a list that hasn't been initialized yet, you'll get NULL. For example

l <- list()
l[[index1]]
# NULL

R happens to have special behavior when you try set a named atomic value on a NULL object. Observe

# NULL[["a"]] <- "character" is basically calling....
`[[<-`(NULL, "a", "character")
#           a 
# "character" 

Note that we are getting a named vector here. Not a list. This is true for your "working" examples as well

l <- list()
l[[index1]][[index2]] <- "character"
class(l[[index1]][[index2]])
# [1] "character"

Also note that this doesn't have anything to do with S4 specifically. The same would happen if we tried to set a more complex objected like a function as well

l <- list()
l[[index1]][[index2]] <- mean
# Error in l[[index1]][[index2]] <- mean : 
#   invalid type/length (closure/0) in vector allocation

In languages like Perl you can "magically" bring hashes to life with the correct indexing syntax via autovivification, but that's not true in R. If you want a list() to exist at l[[index1]] you will need to explicitly create it. This will work

l <- list()
l[[index1]] <- list()
l[[index1]][[index2]] <- s

Again this is because [[ ]] is a bit ambiguous in R. It's a generic indexing function not used exclusively with lists.

like image 168
MrFlick Avatar answered Oct 06 '22 01:10

MrFlick