是否允许双链结构?

问题描述 投票:0回答:1

我正在编写一个带有 S4 类的包,它看起来像一个简单的树结构:该类,比如说

S4node
,有一个槽
nodes
,它是子
S4node
的列表(通过一个共同的虚拟祖先,比如说
 S4base
)。该类还有一个类型为
parent
的插槽
S4base
,它链接回子节点的父节点。看起来或多或少像这样(为了清晰起见,使用了准系统编码):

# Create the root node, slot parent is set to NA, slot id is set to 567
> root <- new_node(567) 

# Create some child nodes, slot parent is set to root, slot nodes has new node added
> root <- add_node(root, 5671)
> root <- add_node(root, 5672)

工作正常,所有插槽均设置正确。向下遍历层次结构和向上遍历层次结构都有效。但问题是:当我想向上遍历层次结构时,

nodes
插槽设置为
NULL
,这在向下移动其他分支时变得很明显。像这样:

> node5671 <- find_node(root, 5671)

# Now traverse 5671 -> 567 -> 5672
> node5672 <- node_travel(node5671, "../5672")
Error: path not found

在控制台上,这变得更加清晰:

> length(root@nodes)
[1] 2
> node5671@parent@id
[1] 567
> nodes5671@parent@nodes
NULL

# Best one yet: take the root node, get a child, get the parent (= root), get the nodes = NULL!!!
> root@nodes[[1]]@parent@nodes
NULL

在我看来,带有节点的列表会自动清空,但只有在隐式访问时:我可以首先构造列表,只有当通过

@parent
查找引用列表时,列表才会被清空。这是为了避免无限递归吗?这是
gc()
的怪癖吗?有解决方法吗?

r
1个回答
0
投票

我只能假设

add_node
修改其参数的
copy
nodes 槽并返回修改后的 copy。 副本获得一个新节点,并保留原始节点。 使用
tracemem
...

设计一个示例并不难
> setClass("S4base")
> setClass("S4root",
+          contains = "S4base",
+          slots = c(id = "integer", parent = "NULL", nodes = "list"),
+          prototype = list(id = 0L, parent = NULL, nodes = list()))
> setClass("S4node",
+          contains = "S4base",
+          slots = c(id = "integer", parent = "S4base", nodes = "list"),
+          prototype = list(id = 1L, parent = new("S4root"), nodes = list()))
> 
> root <- new("S4root", id = 0L); tracemem(root)
[1] "<0x1370506d8>"
> node <- new("S4node", id = 1L, parent = root)
> root@nodes <- list(node)
tracemem[0x1370506d8 -> 0x1370f5aa8]: 
> identical(root, root@nodes[[1L]]@parent)
[1] FALSE
> 
> str(root)
Formal class 'S4root' [package ".GlobalEnv"] with 3 slots
  ..@ id    : int 0
  ..@ parent: NULL
  ..@ nodes :List of 1
  .. ..$ :Formal class 'S4node' [package ".GlobalEnv"] with 3 slots
  .. .. .. ..@ id    : int 1
  .. .. .. ..@ parent:Formal class 'S4root' [package ".GlobalEnv"] with 3 slots
  .. .. .. .. .. ..@ id    : int 0
  .. .. .. .. .. ..@ parent: NULL
  .. .. .. .. .. ..@ nodes : list()
  .. .. .. ..@ nodes : list()
>

要解决 R 中的修改时复制问题,您可能应该使用环境(可能是扩展

environment
的 S4 类):

> root <- new.env(parent = emptyenv()); try(tracemem(root))
Error in tracemem(root) : 
  'tracemem' is not useful for promise and environment objects
> node <- new.env(parent = emptyenv())
> 
> root$id <- 0L
> root$nodes <- list(node)
> 
> node$id <- 1L
> node$nodes <- list()
> node$parent <- root
> 
> identical(root, root$nodes[[1L]]$parent)
[1] TRUE
> 
© www.soinside.com 2019 - 2024. All rights reserved.