R中嵌套列表/数据框全层级字段相对路径高效获取方案问询
目标
本问题关联但未被多个Stack Overflow问答覆盖(具体问答编号已省略)。
我希望在R中创建一个**高效(即快速)**的函数,返回一个character向量,包含任意深度的嵌套list或data.frame中所有字段的相对路径,也可选择仅返回满足指定谓词函数的字段路径。
示例
举例来说,我有如下数据结构(本示例为data.table,也可以是tibble或普通list):
input <- data.table( a = c(1, 2, 3, 4), b = LETTERS[1:4], c = list( list(a = 1, g = 2), list(a = 1), list(a = 1, b = 50), list(a = 1, zeta = data.frame(one = 'two', two = 'three')) ), d = list( data.frame( x = c(1, 2), y = LETTERS[1:2], z = data.frame(a = c("10", "20")) ), data.frame( x = c(3, 4, 5), y = LETTERS[3:5], z = data.frame(a = c("30", "40", "50")) ), data.frame( x = 6, y = LETTERS[6], z = 'another_thing', zz = list(a = "60", p = 'eish') ), data.frame( x = 7:12, y = LETTERS[7:12], z = data.frame(a = as.character(70:75)) ) ) )
基础版本函数应用于input时的期望输出(需严格符合指定格式)如下:
c( "[['a']]", "[['b']]", "[['c']]", "[['c']][[1]]", "[['c']][[1]][['a']]", "[['c']][[1]][['g']]", "[['c']][[2]]", "[['c']][[2]][['a']]", "[['c']][[3]]", "[['c']][[3]][['a']]", "[['c']][[3]][['b']]", "[['c']][[4]]", "[['c']][[4]][['a']]", "[['c']][[4]][['zeta']]", "[['c']][[4]][['zeta']][['one']]", "[['c']][[4]][['zeta']][['two']]", "[['d']]", "[['d']][[1]]", "[['d']][[1]][['x']]", "[['d']][[1]][['y']]", "[['d']][[1]][['a']]", "[['d']][[2]]", "[['d']][[2]][['x']]", "[['d']][[2]][['y']]", "[['d']][[2]][['a']]", "[['d']][[3]]", "[['d']][[3]][['x']]", "[['d']][[3]][['y']]", "[['d']][[3]][['z']]", "[['d']][[3]][['zz.a']]", "[['d']][[3]][['zz.p']]", "[['d']][[4]]", "[['d']][[4]][['x']]", "[['d']][[4]][['y']]", "[['d']][[4]][['a']]" )
即输出需包含根对象input下所有层级字段的完整相对路径列表。
当前方案
我已实现递归函数find_paths,该函数接受以下参数:
.x:待搜索的根嵌套list或data.frame.p:(可选)谓词函数,用于判断是否将某字段路径加入输出max_depth:搜索的最大嵌套深度(可限制初始搜索范围)current_path、current_depth、paths:递归过程中内部更新的参数
find_paths <- function(.x, .p = NULL, max_depth = Inf, current_path = '', current_depth = 0, paths = NULL) { # 达到最大深度时停止搜索 if (current_depth > max_depth) return(paths) # 应用指定的谓词函数 if (is.function(.p)) { if (current_depth > 0 & .p(.x)) { paths <- c(paths, current_path) } } else { if (current_depth > 0) { paths <- c(paths, current_path) } } # 递归部分:判断是否为列表并继续构建路径 if (is.list(.x)) { if (is.null(names(.x))) { for (i in seq_along(.x)) { new_path <- paste0(current_path, "[[", i, "]]") paths <- find_paths( .x = .x[[i]], .p = .p, max_depth = max_depth, current_path = new_path, current_depth = current_depth + 1, paths = paths ) } } else { for (name in names(.x)) { new_path <- paste0(current_path, "[['", name, "']]") paths <- find_paths( .x = .x[[name]], .p = .p, max_depth = max_depth, current_path = new_path, current_depth = current_depth + 1, paths = paths ) } } } # 返回路径结果 paths } # 不使用谓词的用法(生成上述示例输出) find_paths(.x = input) # 使用谓词的用法(仅返回字符类型元素的路径) find_paths(.x = input, .p = is.character)
该函数在处理input这类对象时可正确生成期望输出,但在处理更大、更复杂的嵌套结构时性能极差(主观判断为难以接受)。我需处理的数据通常包含数十万行,且有数百个深度达8层的嵌套字段。现提出两个问题:
- 我是否忽略了某些关键点?此类任务是否本质上效率低下?递归是否为正确的实现方式?我推测若要应用谓词函数,递归可能不可避免,但希望能有更简便的方法获取R中嵌套对象的所有名称/地址/路径(不确定正确术语)。
- 是否存在更优(即更快)的替代方案?我已尝试过多种方法,但多数方法(如展开根嵌套对象)需对输入对象进行昂贵的转换,抵消了避免递归带来的潜在优势。
内容的提问来源于stack exchange,提问作者hendrikvanb
相关产品推荐
相关产品推荐

