从列表 os 文件路径 (Python) 构造树 - 取决于性能
Posted
技术标签:
【中文标题】从列表 os 文件路径 (Python) 构造树 - 取决于性能【英文标题】:Construct a tree from list os file paths (Python) - Performance dependent 【发布时间】:2011-12-13 05:55:55 【问题描述】:嘿,我正在开发一个用 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]]]
类似的东西。我一直在尝试一些想法,但没有一个能提供我想要的速度。
注意:我已经有了路径列表,所以不用担心。该函数获取路径列表并给出树列表。
提前致谢
【问题讨论】:
« 我正在开发高性能文件管理/分析工具包用python编写。»。 ..哎哟! :( 哈哈,我知道,我想先实现一些合理的实现,然后我将使用 cython 等更底层的实现...... 【参考方案1】:现在您已经进一步澄清了问题,我想以下是您想要的:
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/
之间的区别。我认为这有助于您快速区分叶子是目录还是文件。
我希望这能回答您的问题。如果有任何不清楚的地方,请发表评论。
【讨论】:
好的,谢谢,这很有帮助,而且工作正常。我可能会改变我索引文件的方式,这样我就可以让基于它的一切变得更有效率。但是,是的,非常感谢! @cwoebker - 没问题,很高兴它有帮助!祝你的问题好运! 感谢您的代码/操作方法@mac,它对我很有用,但我希望我的树在每个级别按字母顺序排序。我发现了这个:[链接]***.com/questions/21024969/…,但我没有让它与这棵树一起工作。谁能解释我如何正确使用“排序”功能或指向我一些关于此的“新手”课程。谢谢! 这是很棒的酱汁。但为什么它会取消排序我的排序输入? nm,我知道我可以简单地在 d.items 上添加一个排序操作【参考方案2】:我并不完全清楚你拥有什么和你需要什么(提供一些你拥有的太慢的代码可能会有所帮助),但你可能应该将你的路径名分解为目录名和基本名,然后使用特制的类或至少是列表或字典的层次结构从中构建一棵树。然后各种遍历应该允许您以几乎任何您需要的方式进行序列化。
关于性能问题,您是否考虑过使用 Pypy、Cython 或 Shedskin?我有一个我一直在研究的重复数据删除备份系统,它可以在 Pypy 或 Cython 上运行相同的代码;在 Pypy 上运行它实际上优于 Cython 增强版本(在 32 位上运行很多,在 64 位上运行一点点)。我也很想比较 shedskin,但它显然无法跨越 shedskin/cpython 边界。
此外,当您遇到性能问题时,分析是必不可少的 - 至少,如果您已经选择了合适的算法。
【讨论】:
Cython 计划在以后使用。【参考方案3】:首先,“非常高性能”和“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! :)
【讨论】:
这确实很快,但与我的问题无关,我需要用正则表达式或其他东西分析我所有的路径,然后得到一个像你在输入中使用的树结构 @cwoebker - 你可能应该澄清你的问题,就像现在一样,不清楚你的输入和预期输出是什么。这也有助于了解您是否有权访问文件系统并可以从中读取文件名,或者您是否必须使用您希望举例说明的输入。 :) 我添加了示例输入...我确实可以访问文件系统。在项目中,我有一个 redis 实例中的文件索引,我从那里读取了路径,所以我不想再次访问这些文件 我认为在谈论 python 的高性能时提到切换到 c 是陈词滥调。每个人都知道这一点,但您并没有看到每个人都切换回 c。每种语言都有自己的目的,很明显 OP 意味着最快的算法,即在 Python 中实现的时间最短的算法。以上是关于从列表 os 文件路径 (Python) 构造树 - 取决于性能的主要内容,如果未能解决你的问题,请参考以下文章