R语言中如何基于列表元素递归重命名嵌套列表
R语言中如何基于列表元素递归重命名嵌套列表
嗨,我来帮你搞定这个嵌套列表递归重命名的问题!你手里的这个多层嵌套列表,每个节点都带着text字段,想要把每个层级的列表元素用对应的text值来命名,而不是像现在这样手动硬编码对吧?手动硬编码虽然能解决简单的层级,但列表结构一复杂就完全没法用了,递归方法才是正道。
先来看你的示例数据:
nodes <- list( list( text = "RootA", children = list( list(text = "ChildA1"), list(text = "ChildA2") ) ), list( text = "RootB", children = list( list(text = "ChildB1"), list(text = "ChildB2") ) ) )
你之前用的硬编码方式确实能得到想要的结果,但扩展性太差:
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)
下面给你几个通用的递归解决方案,还附上了性能对比:
1. 自定义递归函数(最快方案)
这个函数是网友@knitz3提供的,逻辑清晰而且性能最优,先判断当前列表的每个元素都包含text字段,就给列表元素命名,然后递归处理每个元素的children子列表:
list_rename_recursive <- function(x) { # 检查当前列表的所有元素都有text字段 if (is.list(x) && all(sapply(x, function(y) "text" %in% names(y)))) { # 用每个元素的text值作为列表名 names(x) <- sapply(x, `[[`, "text") # 递归处理每个元素的children(如果存在的话) x <- lapply(x, function(y) { if ("children" %in% names(y)) { y$children <- list_rename_recursive(y$children) } y }) } x } # 调用函数 nodes_named <- list_rename_recursive(nodes) # 查看结果 str(nodes_named)
2. 使用purrr包的modify_tree
如果你习惯用tidyverse系列的工具,可以用purrr::modify_tree来处理,不过性能会稍慢一些:
library(purrr) # 先处理子层级,再给顶层命名 nodes_named <- modify_tree(nodes, branch = function(x) { if ("children" %in% names(x)) { names(x$children) <- map_chr(x$children, "text") } x }) names(nodes_named) <- map_chr(nodes_named, "text") str(nodes_named)
3. 另一种递归实现方案
这个方案逻辑和第一个类似,写法稍有不同,性能介于前两者之间:
names_text <- function(x) { if (is.list(x)) { # 如果当前是包含多个节点的列表(每个节点有text) if (all(sapply(x, function(node) "text" %in% names(node)))) { names(x) <- sapply(x, `[[`, "text") x <- lapply(x, names_text) } else if ("children" %in% names(x)) { # 如果是单个节点,处理它的children x$children <- names_text(x$children) } } x } nodes_named <- names_text(nodes) str(nodes_named)
性能对比
我特意做了基准测试,结果如下,能看到第一个自定义递归函数的速度优势很明显:
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
备注:内容来源于stack exchange,提问作者ahnungslos
相关产品推荐
相关产品推荐

