Представление дерева каталогов в виде рекурсивного списка
Я застрял с определенной задачей. То, что я хочу, это функция, которая, учитывая путь к каталогу, будет возвращать рекурсивный список в качестве вывода.
Выходные данные должны иметь вид myList$dir$subdir$subdir$fullFilePath
Поэтому я хочу представить дерево каталогов в виде определенного списка. Я получаю все файлы, получаю все подкаталоги для каждого файла, но я застрял в том, как бросить все это в список с несколькими уровнями.
3 ответа
Вот решение с использованием рекурсии:
tree.list <- function(file.or.dir) {
isdir <- file.info(file.or.dir)$isdir
if (!isdir) {
out <- file.or.dir
} else {
files <- list.files(file.or.dir, full.names = TRUE,
include.dirs = TRUE)
out <- lapply(files, tree.list)
names(out) <- basename(files)
}
out
}
Я проверил это здесь в небольшом каталоге
test.dir <- tree.list("./test")
test.dir
# $a
# $a$`1.txt`
# [1] "./test/a/1.txt"
#
# $a$aa
# $a$aa$`2.txt`
# [1] "./test/a/aa/2.txt"
#
# $b
# $b$`3.txt`
# [1] "./test/b/3.txt"
Если это слишком медленно для ваших нужд, я бы рассмотрел чтение всех файлов в один вызов list.files
с recursive = TRUE
затем сделайте небольшой разбор.
Вот уродливый хак.
mypath <- 'a/b/c/d'
makelist <- function(filepath, fsep = '/'){
unlisted <- unlist(strsplit(filepath, fsep))
nsubs <- length(unlisted)
mylistcall <- paste(paste(rep('list(', nsubs), unlisted, collapse = '='),
'= NULL', paste(rep(')', nsubs), collapse = ''))
mylist <- eval(parse(text = mylistcall))
return(mylist)
}
makelist(mypath)
$a
$a$b
$a$b$c
$a$b$c$d
NULL
Вспоминая
fortune(106)
If the answer is parse() you should usually rethink the question.
-- Thomas Lumley
R-help (February 2005)
Однако в этом случае я бы сказал, что должен переосмыслить ответ.
Вот более короткий вариант замечательного решения @flodel, использующего purrr
пакет:
library( purrr )
tree_list <- function( file_or_dir ) {
f <- partial(list.files, full.names=TRUE, include.dirs=TRUE) %>%
compose(tree_list, .)
file_or_dir %>% set_names( basename(.) ) %>% map_if(dir.exists, f)
}
Первая строка определяет функцию f
что расширяет свой аргумент, используя list.files( ..., full.names=TRUE, include.dirs=TRUE)
затем применяется tree_list()
на расширение.
Вторая строка применяет определенную функцию f
для всех каталогов в исходном аргументе.