I have a nested list in the global environment of a R script.
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
)
While running my process I interactively select elements via the id (100,200, ...). In return a want to add, delete or move elements in the list.
For this reason I thought of using a recursive function to navigate through the list:
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)
This functions returns the list() found in the sublist element of the matching element in the 'anno'-list. My problem is the global environment of R. If I manipulate something ( delete, add, move something within the returned sublist ) i need to reset the global variable with <<-
. But in the case of a recursive function I only hold the current sublist in the context where the parent_id matches. How could one reference a global nested list in R while navigating though it via an recursive function? Is that even possible in R?
The calls I want to carry out in order to delete, add, or move elements in the list 'anno' are:
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.
The tricky part though is that I don't know how deep the recursive structure is. Normally I would use element references to manipulate them directly but how could a solution for manipulation of nested lists in R look like if I want to use recursion?
If possible, have the recursive function take a list, alter that, and return the new version. The reason I suggest this is because it's idiomatic R. R leans toward being a functional language, and part of that means state-based actions are discouraged. In general, functions should only modify state if that's all they do. For example, scale(x)
doesn't affect the value stored in the x
variable. But x <- scale(x)
does, because the <-
function (yes, it's a function) is meant to modify state.
Also, don't worry about memory unless you know it will be a problem based on past experience. Behind the scenes, R is pretty good at preventing needless copying, so trust it to do the right thing. This lets you work with simpler mental models.
A skeleton of how to recursively modify a list, without affecting the original:
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"
If you absolutely need to modify an item in the global namespace, use environments instead of lists.
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"
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.