【发布时间】:2018-03-25 16:54:10
【问题描述】:
我有一个文件和目录的列表。我正在尝试编写一个函数来删除条目,其中还有一个祖先目录的条目。到目前为止我所拥有的似乎有效,但我认为它效率低下,因为它会测试每个文件的完整目录列表。
也许有一个图书馆可以做到这一点,但我找不到它。目的是允许用户选择要上传的文件和目录列表。
从示例中可以看出,目录是条目的子集。我宁愿只提供条目。
import os
def remove_redundant_entries(entries, directories):
result = []
for entry in entries:
# make a copy and successively get the dirname and test it
partial_path = entry
found = False
while partial_path != os.sep:
partial_path = os.path.dirname(partial_path)
if partial_path in directories:
found = True
break
if not found:
result.append(entry)
return result
entries = [
"/home/fred/work/f1.txt",
"/home/fred/work/f2.txt",
"/home/fred/play/f3.txt",
"/home/fred/play",
"/home/jane/dev/f1.txt",
"/home/jane"]
directories = [
"/home/fred/play",
"/home/jane"]
print remove_redundant_entries(entries, directories)
# result:
['/home/fred/work/f1.txt', '/home/fred/work/f2.txt', '/home/fred/play', '/home/jane']
如果您知道某个库或可以提供更好算法的线索,我将不胜感激。同时,我将尝试基于条目排序的方法,因为在列表中祖先应该总是在他们的孩子之前。
编辑:-结果
我通过带有测试集的分析器运行了所有解决方案 10,000 次 - 并添加了一个文件 /home/fred/work/f2.txt.bak 以测试确保常规文件名确实会导致另一个文件被丢弃。
我的原码:1060004 function calls in 0.394 seconds
Stephen Rauch 的回答 - 第一次工作:3250004 function calls in 2.089 seconds
carrdelling 的回答 - 不适用于类似的文件名:480004 function calls in 0.146 seconds
carrdelling 编辑的答案 - 适用于所有情况:680004 function calls in 0.231 seconds
感谢所有贡献的人!
【问题讨论】:
-
使用可用于字符串对象的
startswith方法会不会更简单。这样,对于每个条目,您可以根据它以任何目录字符串开头来决定是否保留它?作为一种算法并不真正简单,但它删除了 while 循环。 -
我确实尝试过
startswith,但可能存在一个常规文件以另一个常规文件的名称开头的情况:/somepath/foo.txt.bak , /somepath/foo.txt。话虽如此,它可能是一个正则表达式可以做到吗? -
您不需要正则表达式 - 请参阅我更新的答案,如果您正确排序输入列表,那么您应该能够同时保留
/somepath/foo.txt.bak和/somepath/foo.txt,即使使用startswith