使用表达式根据属性对 R6Class 进行子集化
Use an expression to subset R6Class based on attributes
我有一个 R6 class BarContainer
,其中包含 Bar
的向量,其中 Bar
是另一个 R6 class。我想在 BarContainer
中实现一个方法 subset
,它将 Bar
的向量子集化以匹配作为参数给出的表达式。
Bar = R6::R6Class(
### Class name
"Bar",
### Public members
public = list(
### Attributes
a = -1,
b = -1,
c = -1,
### Initialize
initialize = function(A, B, C)
{
self$a = A
self$b = B
self$c = C
}
)
)
BarContainer = R6::R6Class(
### Class name
"BarContainer",
### Public members
public = list(
### Attributes
self$bars = c(),
### Initialize
initialize = function(input)
{
bars = input
}#,
### Subset
subset = function(expr)
{
# ??? self[eval(parse(text=expr))] ???
}
)
)
这是 subset
的可能用例
mySubsettedContainer = myContainer$subset(a == 3 && (b > 0 || c > 0) )
如何实现?任何其他解决方案(最终使用多个表达式或其他东西)来实现此 subset
方法?
请注意,Bar
有一大堆有用的方法,这种 oop 方法真的很干净。我想避免将我的 Bar
对象保留为 data.frame
的行(例如 bars = data.frame(a = .., b = .., c = ..)
),即使它会在 [=12= 中实现 subset
方法] 容易多了。
如果您希望 BarContainer$subset
以这种方式工作,您将需要捕获表达式并对 BarContainer
中的每个 Bar
求值以获得逻辑向量,然后使用这对容器中的 bars
字段进行子集化。 Bar
对象的结果列表然后可以传递给 BarContainer$new
调用 return 一个新的 BarContainer
与子集 Bar
对象。
您可以使用 match.call()
捕获表达式并使用 lapply
在每个 Bar
的上下文中对其求值,尽管您需要将每个 Bar
表示为在 lapply
中列出,使其成为有效的评估上下文。这意味着实现看起来像这样:
BarContainer = R6::R6Class(
### Class name
"BarContainer",
### Public members
public = list(
### Attributes
bars = c(),
### Initialize
initialize = function(input)
{
self$bars = input
},
### Subset
subset = function(expr)
{
ex <- as.list(match.call()[-1])$exp
ss <- sapply(self$bars, function(x){
eval(ex, envir = as.list(x), enclos = parent.frame())})
return(BarContainer$new(self$bars[ss]))
}
)
)
所以我们可以像这样创建一个示例设置:
# Create 4 Bars for our container:
bar1 <- Bar$new(1, 1, 1)
bar2 <- Bar$new(2, 2, 2)
bar3 <- Bar$new(3, 3, 3)
bar4 <- Bar$new(4, 4, 4)
# Populate our container:
bar_container <- BarContainer$new(c(bar1, bar2, bar3, bar4))
我们的子集函数按预期工作:
subsetted_container <- bar_container$subset(a > 1 & c < 4)
subsetted_container$bars
#> [[1]]
#> <Bar>
#> Public:
#> a: 2
#> b: 2
#> c: 2
#> clone: function (deep = FALSE)
#> initialize: function (A, B, C)
#>
#> [[2]]
#> <Bar>
#> Public:
#> a: 3
#> b: 3
#> c: 3
#> clone: function (deep = FALSE)
#> initialize: function (A, B, C)
请记住,子集 BarContainer
不会包含原始 Bar
对象的 副本 ,而是指向对象本身的指针。因此,如果您更改子集容器中的第一个 Bar
,它将更改非子集容器中的 bar2
和第二个 Bar
。我猜这是无论如何都需要的行为,但如果不是,你将不得不深度克隆每个 Bar
作为你的子集方法的一部分。
我有一个 R6 class BarContainer
,其中包含 Bar
的向量,其中 Bar
是另一个 R6 class。我想在 BarContainer
中实现一个方法 subset
,它将 Bar
的向量子集化以匹配作为参数给出的表达式。
Bar = R6::R6Class(
### Class name
"Bar",
### Public members
public = list(
### Attributes
a = -1,
b = -1,
c = -1,
### Initialize
initialize = function(A, B, C)
{
self$a = A
self$b = B
self$c = C
}
)
)
BarContainer = R6::R6Class(
### Class name
"BarContainer",
### Public members
public = list(
### Attributes
self$bars = c(),
### Initialize
initialize = function(input)
{
bars = input
}#,
### Subset
subset = function(expr)
{
# ??? self[eval(parse(text=expr))] ???
}
)
)
这是 subset
mySubsettedContainer = myContainer$subset(a == 3 && (b > 0 || c > 0) )
如何实现?任何其他解决方案(最终使用多个表达式或其他东西)来实现此 subset
方法?
请注意,Bar
有一大堆有用的方法,这种 oop 方法真的很干净。我想避免将我的 Bar
对象保留为 data.frame
的行(例如 bars = data.frame(a = .., b = .., c = ..)
),即使它会在 [=12= 中实现 subset
方法] 容易多了。
如果您希望 BarContainer$subset
以这种方式工作,您将需要捕获表达式并对 BarContainer
中的每个 Bar
求值以获得逻辑向量,然后使用这对容器中的 bars
字段进行子集化。 Bar
对象的结果列表然后可以传递给 BarContainer$new
调用 return 一个新的 BarContainer
与子集 Bar
对象。
您可以使用 match.call()
捕获表达式并使用 lapply
在每个 Bar
的上下文中对其求值,尽管您需要将每个 Bar
表示为在 lapply
中列出,使其成为有效的评估上下文。这意味着实现看起来像这样:
BarContainer = R6::R6Class(
### Class name
"BarContainer",
### Public members
public = list(
### Attributes
bars = c(),
### Initialize
initialize = function(input)
{
self$bars = input
},
### Subset
subset = function(expr)
{
ex <- as.list(match.call()[-1])$exp
ss <- sapply(self$bars, function(x){
eval(ex, envir = as.list(x), enclos = parent.frame())})
return(BarContainer$new(self$bars[ss]))
}
)
)
所以我们可以像这样创建一个示例设置:
# Create 4 Bars for our container:
bar1 <- Bar$new(1, 1, 1)
bar2 <- Bar$new(2, 2, 2)
bar3 <- Bar$new(3, 3, 3)
bar4 <- Bar$new(4, 4, 4)
# Populate our container:
bar_container <- BarContainer$new(c(bar1, bar2, bar3, bar4))
我们的子集函数按预期工作:
subsetted_container <- bar_container$subset(a > 1 & c < 4)
subsetted_container$bars
#> [[1]]
#> <Bar>
#> Public:
#> a: 2
#> b: 2
#> c: 2
#> clone: function (deep = FALSE)
#> initialize: function (A, B, C)
#>
#> [[2]]
#> <Bar>
#> Public:
#> a: 3
#> b: 3
#> c: 3
#> clone: function (deep = FALSE)
#> initialize: function (A, B, C)
请记住,子集 BarContainer
不会包含原始 Bar
对象的 副本 ,而是指向对象本身的指针。因此,如果您更改子集容器中的第一个 Bar
,它将更改非子集容器中的 bar2
和第二个 Bar
。我猜这是无论如何都需要的行为,但如果不是,你将不得不深度克隆每个 Bar
作为你的子集方法的一部分。