将目录树表示为递归列表

9
我遇到了一个问题。我希望有一个函数,给定一个目录路径,它能够返回一个递归列表作为输出。
输出应该是这样的形式:myList$dir$subdir$subdir$fullFilePath
所以基本上我想将目录树表示为特定的列表。我获取所有文件,获取每个文件的所有子目录,但我不知道如何将它们全部放入一个具有多个级别的列表中。
3个回答

7

这里是使用递归的解决方案:

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"

如果这个速度对您的需求来说太慢了,可以考虑使用recursive = TRUE把所有文件读入一个list.files中,然后再进行一些解析。

1
谢谢!这太优美了,好到让人心痛。 - Karolis Koncevičius
现在它不会太慢。至于解析 - 我仍然不知道如何在解析后制作递归列表。在strsplit之后,我会有这样的东西:list(dir=myDir,subdir1=mySubdir1,subdir2=mySubdir2,file=myFile)。循环将无法使用list [ ["myDir"]] [[mySubdir1]] [[mySubdir2]] [[myFile]] <- file,因为我无法在循环中指定所需的级别数。再次感谢您的答案。 - Karolis Koncevičius

2

这是一种不太正规的方法。

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提供了一个更简洁的答案。如果不是这样,我很乐意接受你的答案。 - Karolis Koncevičius
顺便提一下,我注意到了 - 你那个 fortune 是什么东西? - Karolis Koncevičius
1
@KarolisKoncevičius。请查看http://cran.r-project.org/web/packages/fortunes/index.html。 - mnel

1
这是@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应用于原始参数中的所有目录。

我希望在费力地做之前看到这个! - Nate Lockwood

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接