R6类,以命名列表的形式获取所有字段

cuxqih21  于 2023-05-26  发布在  其他
关注(0)|答案(3)|浏览(97)

我想以列表的形式检索R6Class对象的所有属性的值。这些值最好与属性名称一起提供。理想情况下,这可以一般地编写,以便它也适用于继承的类。不幸的是,R6的文档并不那么全面,我找不到一个类似的问题。
下面的基本示例将演示我目前拥有的以及目标解决方案应该是什么样子。

Person <- R6::R6Class("Person", public = list(
  age = NULL,
  gender = NULL,
  
  initialize = function(age, gender = "M") {
    self$age <- age
    self$gender <- gender
  },
  
  list_attributes = function(){
    return(list(self$age, self$gender))
  }
))

p <- Person$new(age=42, gender="W")
p$list_attributes()

# Output
> [[1]]
> [1] 42

> [[2]]
> [1] "W"

list_attributes部分地实现了我想要的功能,但我认为应该有一种更好的方法来获取所有公共属性,而不是显式地命名所有公共属性。我发现使用str(p)我可以得到一些关于我的对象的信息,但不是以我想要的形式。

> str(p)
Classes 'Person', 'R6' <Person>
  Public:
    age: 42
    clone: function (deep = FALSE) 
    gender: W
    initialize: function (age, gender = "M") 
    list_attributes: function ()

我想要的outut会喜欢:

list(age=42, gender="M")
$age
[1] 42

$gender
[1] "M"

有没有人知道如何实现这一点?

ibrsph3r

ibrsph3r1#

谢谢你的提问和回答,我也在为同样的问题而挣扎。
这个问题链接到我最近提出的一个问题,关于在对象here中更改self的类。
正如向我解释的那样,可以使用class(self)访问对象中的对象类,因此不需要使用私有的“class”字段,因此您的问题可以使用your对象结构来解决:

Person <- R6::R6Class("Person",                     
                      
                      public = list(
                        age = NULL,
                        gender = NULL,
                        
                        initialize = function(age, gender = "M") {
                          self$age <- age
                          self$gender <- gender
                        },
                        
                        public_fields = function(){
                          return(names(get(class(self))$public_fields))
                        },
                        
                        list_attributes = function(){
                          
                          values <- purrr::map(self$public_fields(), ~.subset2(self, .x))
                          names(values) <- self$public_fields()
                          
                          return(values)
                        }
                      ))

其给出:

> p <- Person$new(age=42, gender="W")
> p$public_fields()
[1] "age"    "gender"
> p$list_attributes()
$age
[1] 42

$gender
[1] "W"

,将所有内容放在一个active字段中,并使用set_names()

Person <- R6::R6Class("Person",                     
                      
                      public = list(
                        age = NULL,
                        gender = NULL,
                        
                        initialize = function(age, gender = "M") {
                          self$age <- age
                          self$gender <- gender
                        }
                        ),
                      active = list(
                        
                        my_fields = function(){
                          purrr::map(names(get(class(self))$public_fields), ~.subset2(self, .x)) %>% 
                            set_names(names(get(class(self))$public_fields))
                        }
                      ))

其给出:

> p <- Person$new(age=42, gender="W")
> p$my_fields
$age
[1] 42

$gender
[1] "W"
n3schb8v

n3schb8v2#

R6::Class打印函数的source code帮助我更接近我想要的解决方案。

Person <- R6::R6Class("Person",
  
  private = list(
    class = Person
  ),                      
  
  public = list(
    age = NULL,
    gender = NULL,
  
    initialize = function(age, gender = "M") {
      self$age <- age
      self$gender <- gender
    },
    
    public_fields = function(){
      return(names(private$class$public_fields))
    },
  
  list_attributes = function(){
    
    values <- purrr::map(self$public_fields(), ~.subset2(self, .x))
    names(values) <- self$public_fields()
    
    return(values)
  }
))

现在函数产生了想要的输出,但是我必须指定我现在已经做的类作为私有成员变量。如果这可以动态地完成,我会很高兴。
现在的输出是:

> p <- Person$new(age=42, gender="W")
> p$list_attributes()
$age
[1] 42

$gender
[1] "W"
vulvrdjw

vulvrdjw3#

在上面的答案中,提取字段与类耦合。我更喜欢使用一个函数来提取字段和字段值。因此,我可以使用它与任何R6类。

Person <- R6::R6Class("Person", public = list(
  age = NULL,
  gender = NULL,
  
  initialize = function(age, gender = "M") {
    self$age <- age
    self$gender <- gender
  }))
p <- Person$new(age=42, gender="W")
R6_extract_values <- function(r6class){
  tmp <- sapply(r6class, class)
  slots <- tmp[ !tmp %in% c("environment", "function")]
  res <- list()
  for (i in names(slots)) {
    if ("R6" %in% class(r6class[[i]])) {
      res[[i]]  <- R6_extract_values(r6class[[i]])
    }else{
      res[[i]] <- r6class[[i]]
    }
  }
  return(res)
}

sapply(r6class, class)执行此工作(提取所有插槽及其类。剩下的就是提取值,如果插槽不是环境或函数的话。
然后

> R6_extract_values(p)
$gender
[1] "W"

$age
[1] 42

相关问题