从列表os文件路径构建树(Python) - 依赖于性能

时间:2011-12-13 05:55:55

标签: python recursion path tree

嘿,我正在开发一个用python编写的高性能文件管理/分析工具包。 我想创建一个函数,以树格式给我一个列表或类似的东西。 像question (java-related)

这样的东西

自:

dir/file
dir/dir2/file2
dir/file3
dir3/file4
dir3/file5

注意:路径列表未排序

要:

dir/
    file
    dir2/
        file2
    file3
dir3/
    file4
    file5

[[dir, [file, [dir2, [file2]], file3]], [dir3, [file4, file5]]]

沿着这些方向的东西。我一直在玩一些想法,但没有一个能提供我想要的速度。

注意:我已经有路径列表,所以不用担心。该函数采用路径列表并给出树列表。

先谢谢

3 个答案:

答案 0 :(得分:15)

既然你已经澄清了这个问题,我想以下是你想要的:

from collections import defaultdict

input_ = '''dir/file
dir/dir2/file2
dir/file3
dir2/alpha/beta/gamma/delta
dir2/alpha/beta/gamma/delta/
dir3/file4
dir3/file5'''

FILE_MARKER = '<files>'

def attach(branch, trunk):
    '''
    Insert a branch of directories on its trunk.
    '''
    parts = branch.split('/', 1)
    if len(parts) == 1:  # branch is a file
        trunk[FILE_MARKER].append(parts[0])
    else:
        node, others = parts
        if node not in trunk:
            trunk[node] = defaultdict(dict, ((FILE_MARKER, []),))
        attach(others, trunk[node])

def prettify(d, indent=0):
    '''
    Print the file tree structure with proper indentation.
    '''
    for key, value in d.iteritems():
        if key == FILE_MARKER:
            if value:
                print '  ' * indent + str(value)
        else:
            print '  ' * indent + str(key)
            if isinstance(value, dict):
                prettify(value, indent+1)
            else:
                print '  ' * (indent+1) + str(value)



main_dict = defaultdict(dict, ((FILE_MARKER, []),))
for line in input_.split('\n'):
    attach(line, main_dict)

prettify(main_dict)

输出:

dir3
  ['file4', 'file5']
dir2
  alpha
    beta
      gamma
        ['delta']
        delta
          ['']
dir
  dir2
    ['file2']
  ['file', 'file3']

有一点需要注意:

  • 该脚本大量使用defaultdicts,基本上这允许跳过检查是否存在密钥及其初始化(如果不存在)
  • 目录名称被映射到字典键,我认为这对你来说可能是一个很好的功能,因为键是经过哈希处理的,你可以用这种方式比列表更快地检索信息。您可以使用main_dict['dir2']['alpha']['beta'] ...
  • 格式访问层次结构
  • 请注意.../delta.../delta/之间的区别。我认为这有助于您快速区分作为目录或文件的叶子。

我希望这能回答你的问题。如果有任何不清楚的地方,请发表评论。

答案 1 :(得分:1)

我不清楚你拥有什么和你需要什么(它可能有助于提供你所拥有的一些太慢的代码),但你可能应该将你的路径名分解为dirnames和basenames,然后使用特制的类或至少是列表或词典的层次结构来构建树。然后,各种遍历应该允许您以几乎任何方式进行序列化。

关于性能问题,你考虑过使用Pypy,Cython或Shedskin吗?我有一个重复数据删除备份系统,我一直在努力,可以在Pypy或Cython上运行相同的代码;在Pypy上运行它实际上优于Cython增强版本(32位上的很多,64位上的一点点)。我也喜欢比较流行皮草,但它显然无法在割皮/ cpython边界产生效果。

此外,如果您遇到性能问题,则需要进行性能分析 - 至少,如果您已经选择了合适的算法。

答案 2 :(得分:0)

首先, “非常高性能”“Python”混合不好。如果您正在寻找的是将性能优化到极致,那么切换到C将为您带来远远优于您可能想到的任何智能代码优化的好处。

其次,很难相信“文件管理/分析工具包” 中的瓶颈将是此功能。磁盘上的I / O操作至少比内存中发生的任何操作慢几个数量级。分析你的代码是衡量这一点的唯一准确方法,但......如果我错了,我准备给你一个披萨! ;)

我建立了一个愚蠢的测试功能,只是为了执行一些初步测量:

from timeit import Timer as T

PLIST = [['dir', ['file', ['dir2', ['file2']], 'file3']], ['dir3', ['file4', 'file5', 'file6', 'file7']]]

def tree(plist, indent=0):
    level = []
    for el in plist:
        if isinstance(el, list):
            level.extend(tree(el, indent + 2))
        else:
            level.append(' ' * indent + el)
    return level

print T(lambda : tree(PLIST)).repeat(number=100000)

输出:

[1.0135619640350342, 1.0107290744781494, 1.0090651512145996]

由于测试路径列表是10个文件,并且迭代次数是100000,这意味着在1秒内您可以处理大约100万个文件的树。现在......除非你在Google工作,否则这对我来说似乎是可以接受的结果。

相比之下,当我开始写这个答案时,我点击了我的主要80Gb HD的根目录上的“属性”选项[这应该是给我我使用C代码的文件数量]。几分钟过去了,我大约50 GB,300000个文件...

HTH! :)