I'd like to recursively rename (or name, as those items are currently unnamed) a list()
based on its items (here text
). There are several similar questions, however I haven't found one with a list structure as follows and I can't seem to find a general recursive approach to solve this.
The example data comes from here:
nodes <- list(
list(
text = "RootA",
children = list(
list(
text = "ChildA1"
),
list(
text = "ChildA2"
)
)
),
list(
text = "RootB",
children = list(
list(
text = "ChildB1"
),
list(
text = "ChildB2"
)
)
)
)
# hard coded solution:
names(nodes) <- c(nodes[[1]]$text, nodes[[2]]$text)
names(nodes[[1]]$children) <- c(nodes[[1]]$children[[1]]$text, nodes[[1]]$children[[2]]$text)
names(nodes[[2]]$children) <- c(nodes[[2]]$children[[1]]$text, nodes[[2]]$children[[2]]$text)
str(nodes)
Expected output:
List of 2
$ RootA:List of 2
..$ text : chr "RootA"
..$ children:List of 2
.. ..$ ChildA1:List of 1
.. .. ..$ text: chr "ChildA1"
.. ..$ ChildA2:List of 1
.. .. ..$ text: chr "ChildA2"
$ RootB:List of 2
..$ text : chr "RootB"
..$ children:List of 2
.. ..$ ChildB1:List of 1
.. .. ..$ text: chr "ChildB1"
.. ..$ ChildB2:List of 1
.. .. ..$ text: chr "ChildB2"
Edit: I just benchmarked the three answer given on my system. The function provided by @knitz3 seems to be the fastest. Thanks everyone - I learned a lot.
Unit: microseconds
expr min lq mean median uq max neval
list_rename_recursive 46.200 64.7010 458.389 79.601 95.2510 36040.6 100
modify_tree 886.102 1929.4005 2787.664 2302.801 2779.1010 18778.5 100
names_text 101.001 207.8015 575.603 246.852 305.9505 30270.8 100
This was fun. I went for something very interpretable. This function loops through every item of the list provided, and calls on itself if an item is itself another list. Should be able to handle unnamed list items as well.
list_rename_recursive <- function(x) {
# If not a list, return the item
if (!is.list(x)) {
return(x)
} else {
# If a list, iterate through the items of the list
for (i in seq_along(x)) {
# If the list item i itself is a list, call
# the function again. The list item is updated
# with the returned value with proper name
# $text if found
if (is.list(x[[i]])) {
name_item <- NA
if (!is.null(x[[i]]$text)) name_item <- x[[i]]$text
x[[i]] <- list_rename_recursive(x[[i]])
if (!is.na(name_item)) names(x)[i] <- name_item
}
}
return(x)
}
}
nodes_new <- list_rename_recursive(nodes)
str(nodes_new)
List of 2
$ RootA:List of 2
..$ text : chr "RootA"
..$ children:List of 2
.. ..$ ChildA1:List of 1
.. .. ..$ text: chr "ChildA1"
.. ..$ ChildA2:List of 1
.. .. ..$ text: chr "ChildA2"
$ RootB:List of 2
..$ text : chr "RootB"
..$ children:List of 2
.. ..$ ChildB1:List of 1
.. .. ..$ text: chr "ChildB1"
.. ..$ ChildB2:List of 1
.. .. ..$ text: chr "ChildB2"