How to look up an R6 object attribute by character vector

471 Views Asked by At

I have the following class which begins as follows:

dataSeries <- R6Class("dataSeries",
                  public = list(
                    geoAccession = NULL,
                    species = NULL,
                    tissue = NULL,
                    seuratObjectPath = NULL,
                    markerType = NULL,
                    clusters = NULL,
                    clusterTable = NULL,
                    clusterSymbols = NULL,
                    clusterPVs = NULL,
                    clusterGIDs = NULL,
                    clusterKGs = NULL,
                    clusterKPs = NULL,
                    clusterKOs = NULL,

I have another class which begins as follows:

metaSeries <- R6Class("metaSeries",
                  public = list(
                    seriesList = NULL,

                    initialize = function(dataDir="Data/Data_Series/Current"){
                      browser()
                      if(!is.null(dataDir)){
                        toProcess = list.files(dataDir,full.names = T)
                        self$seriesList = vector("list", length(toProcess))
                        count = 1
                        for(file in toProcess){
                          series <- readRDS(file)
                          self$seriesList[[count]] <- series
                          count = count + 1
                        }
                      }
                    },
                    findMetaFeatures = function(feature="clusterKPs", rank=3, plot=TRUE){

In practice, metaSeries$seriesList will be initialized as a list of type dataSeries. dataSeries$findMetaFeatures must be able to make calls to dataSeries$seriesList[[i]]$feature where feature is in {clusterGIDs,clusterKGs,clusterKPs,clusterKOs}. By default findMetaFeatures is called with feature="clusterKPs". Within metaSeries$findMetaFeatures, I need a way to match the string "clusterKPs" with the attribute that has that name, when examining some object of type dataSeries located in self$seriesList.

1

There are 1 best solutions below

0
On BEST ANSWER

For future reference, Colin FAY is right; you should provide much more context, and generally should really provide at least the minimum amount of code that would be needed to reproduce your problem to help others actually know what you need help with.

That said, the answer to the question I believe you're asking is relatively simple: you can access public fields of R6 class objects using a character vector by using as.list:

library(R6)
myClass <- R6Class('myClass',
                   public = list(
                       someData = NULL,
                       initialize=function(someData = NA){
                           self$someData <- someData
                       },
                       set_someData = function(val){
                           self$someData <- val
                       }
                   )
)
myObject <- myClass$new(someData='a')
class(myObject)
[1] "myClass" "R6"
class(myObject$someData)
[1] "character"
myObject$someData
[1] "a"
as.list(myObject)[['someData']]
[1] "a"

This could be one way to easily access the same field of many objects of the same R6 class.

EDIT:

After seeing some of your code, I see a little more clearly what you want to accomplish. The answer is the same, you just implement it within a public function of your R6 class like so:

library(R6)
myClass <- R6Class('myClass',
                   public = list(
                       someData = NULL,
                       initialize=function(someData = NA){
                           self$someData <- someData
                       },
                       set_someData = function(val){
                           self$someData <- val
                       },
                       find_features = function(feature='otherData'){
                           if ( !('list' %in% class(self$someData)) ) {
                               if ( !('mySubClass' %in% class(self$someData)) ){
                                   stop('someData does not have the feature')
                               }
                               return(as.list(self$someData)[feature])
                           }
                           return(lapply(self$someData, function(x){
                               as.list(x)[feature]
                           }))
                       }
                   )
)

mySubClass <- R6Class('mySubClass',
                      public = list(
                          otherData = NULL,
                          initialize = function(otherData = NA){
                              self$otherData <- otherData
                          }
                      )
)

mySubObject1 <- mySubClass$new(otherData=1:3)
mySubObject2 <- mySubClass$new(otherData=4:6)
myObject <- myClass$new(someData=list(mySubObject1, mySubObject2))
myObject$find_features()
[[1]]
[[1]]$otherData
[1] 1 2 3


[[2]]
[[2]]$otherData
[1] 4 5 6

You can get rid of one level of the resulting list by using [[feature]] instead of [feature] when defining find_features:

myClass <- R6Class('myClass',
                   public = list(
                       someData = NULL,
                       initialize=function(someData = NA){
                           self$someData <- someData
                       },
                       set_someData = function(val){
                           self$someData <- val
                       },
                       find_features = function(feature='otherData'){
                           if ( !('list' %in% class(self$someData)) ) {
                               if ( !('mySubClass' %in% class(self$someData)) ){
                                   stop('someData does not have the feature')
                               }
                               return(as.list(self$someData)[[feature]])
                           }
                           return(lapply(self$someData, function(x){
                               as.list(x)[[feature]]
                           }))
                       }
                   )
)
myObject <- myClass$new(someData=list(mySubObject1, mySubObject2))    
myObject$find_features()
[[1]]
[1] 1 2 3

[[2]]
[1] 4 5 6