我在R脚本的全局环境中有一个嵌套列表。
anno <- list()
anno[['100']] <- list(
name = "PLACE",
color = "#a6cee3",
isDocumentAnnotation = T,
sublist = list()
)
person_sublist <- list()
person_sublist[['200']] <- list(
name = "ACTOR",
color = "#7fc97f",
isDocumentAnnotation = T,
sublist = list()
)
person_sublist[['300']] <- list(
name = "DIRECTOR",
color = "#beaed4",
isDocumentAnnotation = T,
sublist = list()
)
anno[['400']] <- list(
name = "PERSON",
color = "#1f78b4",
isDocumentAnnotation = T,
sublist = person_sublist
)
在运行我的过程时,我通过id(100,200,...)以交互方式选择元素。作为回报,想要添加,删除或移动列表中的元素。
因此我想到使用递归函数来浏览列表:
searchListId <- function(parent_id = NULL, annotation_system = NULL)
{
for(id in names(annotation_system))
{
cat(paste(id,"\n"))
if(id == parent_id)
{
return(annotation_system[[id]]$sublist)
}
else
{
if(length(annotation_system[[id]]$sublist) > 0)
{
el <- searchListId(parent_id, annotation_system[[id]]$sublist)
if(!is.null(el))
return(el)
}
}
}
return(NULL)
}
searchListId('100', anno)
此函数返回在&#39; anno&#39; -list中匹配元素的子列表元素中找到的list()。我的问题是R的全局环境。如果我操纵某些东西(删除,添加,移动返回的子列表中的内容),我需要用<<-
重置全局变量。但是在递归函数的情况下,我只在parent_id匹配的上下文中保存当前子列表。如何在通过递归函数导航时在R中引用全局嵌套列表?这在R中是否可能?
我想要执行的调用,以便删除,添加或移动列表中的元素&#39; anno&#39;是:
deleteListId('100', anno) #Should return the list without the element 100
addListId('400', anno) #Should return the list with a new element nested in '400'
switchListId('400','200', anno) #Should return a list where the elements with the according keys are switched.
但棘手的部分是我不知道递归结构的深度。通常我会使用元素引用来直接操作它们但是如果我想使用递归,如何在R中操作嵌套列表的解决方案呢?
答案 0 :(得分:2)
如果可能,让递归函数获取列表,更改它,并返回新版本。我之所以这样说是因为它的惯用语R. R倾向于成为一种功能性语言,其中一部分意味着基于国家的行为是不受欢迎的。一般来说,函数应该只修改状态,如果他们所做的那样。例如,scale(x)
不会影响x
变量中存储的值。但x <- scale(x)
确实如此,因为<-
函数(是的,它是一个函数)是为了修改状态。
此外,不要担心内存,除非你知道根据过去的经验这将是一个问题。在幕后,R非常善于防止不必要的复制,所以相信它做正确的事情。这使您可以使用更简单的心理模型。
如何递归修改列表而不影响原始列表的框架:
anno <- list()
anno[['A1']] <- list(
sublist = list(
A3 = list(sublist = NULL),
A4 = list(sublist = list(A6 = list(sublist = NULL))),
A5 = list(sublist = NULL)
)
)
change_list <- function(x) {
for (i in seq_along(x)) {
value <- x[[i]]
if (is.list(value)) {
x[[i]] <- change_list(value)
} else {
if (is.null(value)) {
x[[i]] <- "this ws null"
}
}
}
x
}
change_list(anno)
# $A1
# $A1$sublist
# $A1$sublist$A3
# $A1$sublist$A3$sublist
# [1] "something new"
#
#
# $A1$sublist$A4
# $A1$sublist$A4$sublist
# $A1$sublist$A4$sublist$A6
# $A1$sublist$A4$sublist$A6$sublist
# [1] "something new"
#
#
#
#
# $A1$sublist$A5
# $A1$sublist$A5$sublist
# [1] "something new"
如果您绝对需要修改全局命名空间中的项目,请使用环境而不是列表。
anno_env <- new.env()
anno_env[["A1"]] <- new.env()
anno_env[["A1"]][["sublist"]] <- new.env()
anno_env[["A1"]][["sublist"]][["A3"]] <- NULL
anno_env[["A1"]][["sublist"]][["A4"]] <- NULL
change_environment <- function(environ) {
for (varname in ls(envir = environ)) {
value <- environ[[varname]]
if (is.environment(value)) {
change_environment(value)
} else {
environ[[varname]] <- "something new"
}
}
}
change_environment(anno_env)
anno_env[["A1"]][["sublist"]][["A3"]]
# [1] "something new"