R语言:使用set_names结合map构建目录嵌套列表失败问题
问题描述
首先创建测试目录结构:
c("Level1/Level1A/Level1AA", "Level1/Level1A/Level1AB", "Level1/Level1B/Level1BA", "Level1/Level1B/Level1BB", "Level2/Level2A/Level2AA", "Level2/Level2A/Level2AB", "Level2/Level2B/Level2BA", "Level2/Level2B/Level2BB") %>% map(dir.create, recursive = T)
需要生成与该目录结构一致的命名嵌套列表,且必须采用tidyverse风格。
前期尝试的代码运行正常:
list.dirs(recursive = F) %>% map(list.dirs, recursive = F) %>% set_names(str_split(., "/") %>% map(pluck, 2))
输出结果符合预期:
$Level1 [1] "./Level1/Level1A" "./Level1/Level1B" $Level2 [1] "./Level2/Level2A" "./Level2/Level2B"
但继续构建下一级列表时,代码运行出错:
list.dirs(recursive = F) %>% map(list.dirs, recursive = F) %>% set_names(str_split(., "/") %>% map(pluck, 2)) %>% map_depth(2, list.dirs, recursive = F) %>% map(set_names, str_split(., "/") %>% map_depth(2, pluck, 3))
错误输出中,子级列表的名称变成了list(NULL, NULL, ...),而非预期的Level1A这类名称:
$Level1 $Level1$`list(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)` [1] "./Level1/Level1A/Level1AA" "./Level1/Level1A/Level1AB" $Level1$`list(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)` [1] "./Level1/Level1B/Level1BA" "./Level1/Level1B/Level1BB" $Level2 $Level2$`list(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)` [1] "./Level2/Level2A/Level2AA" "./Level2/Level2A/Level2AB" $Level2$`list(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)` [1] "./Level2/Level2B/Level2BA" "./Level2/Level2B/Level2BB"
期望输出结构:
list(Level1 = list(Level1A = c("Level1AA", "Level1AB"), Level1B = c("Level1BA", "Level1BB")), Level2 = list(Level2A = c("Level2AA", "Level2AB"), Level2B = c("Level2BA", "Level2BB")))
解决方案
之前的错误在于set_names的使用时机和层级处理逻辑有误,应该在每一层级遍历的同时完成路径提取和命名,同时处理最底层的目录名称。
以下是正确的tidyverse风格管道代码:
list.dirs(recursive = TRUE, full.names = FALSE) %>% # 过滤掉根目录 discard(~ . == ".") %>% # 将每个目录路径拆分为三级层级部分 map(str_split_fixed, pattern = "/", n = 3) %>% # 转换为数据框方便分组处理 bind_rows() %>% set_names(c("level1", "level2", "level3")) %>% # 按一级、二级目录分组,收集三级目录为向量 group_by(level1, level2) %>% summarise(level3 = list(level3), .groups = "drop") %>% # 按一级目录分组,将二级目录与对应三级列表组合为嵌套子列表 group_by(level1) %>% summarise(nested = list(deframe(tibble(level2, level3))), .groups = "drop") %>% # 转换为最终的命名嵌套列表 deframe()
代码说明
- 用
list.dirs获取所有目录,通过full.names = FALSE只保留相对路径名称,同时过滤掉根目录.; - 将每个路径拆分为三级目录部分,转换为数据框后按一级、二级目录分组;
- 分组后将三级目录收集为向量,再以二级目录为名称、三级向量为值构建子列表;
- 最后通过
deframe将一级目录设为顶级列表的名称,得到符合要求的嵌套结构。
运行上述代码后,输出结果与期望结构完全一致。
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

