查找子目录路径的最有效方法

问题描述 投票:1回答:2

假设我具有以下目录结构

PROJECT
|
+ BUILD
|    |
|    + STH1
|    |    |
|    |    + 6.11.2
|    |    |
|    |    + 6.11.3
|    |    |
|    |    + .....
|    + STH2
|    |    |
|    |    + 6.11.2
|    |    |
|    |    + 6.11.3
|    |    |
|    |    + .....
+ COMMON
|    |
|    + 6.11.2
|    |
|    + ....

在python的PROJECT目录中找到所有6.11.2目录的最有效方法是什么?

我尝试使用

glob.glob('PROJECT/**/6.11.2', recursive=True)

它有效,但是对我来说不是最佳解决方案,因为它还会查找类似的目录

PROJECT/BUILD/STH1/6.11.2/6.11.2

因此花费很多时间,我只需要找到目录6.11.2的第一个匹配项,因此深入搜索它是浪费时间(同样,sth / 6.11.2 / 6.11.2这样的情况也不会发生在我的结构中)

是否有更好的方法在python中进行搜索?

请注意,6.11.2也是一个非常复杂的目录,包含许多文件和子目录,这就是为什么要花很多时间递归进行搜索的原因。

python algorithm directory glob os.path
2个回答
0
投票

之所以变慢,可能是因为与文件的嵌套比6.11.2目录更多。看看将/附加到您的模式是否有助于忽略文件。

此外,请尝试使用迭代器版本iglob,它将节省glob将所有内容都放入列表中的成本。

filter(lambda p: p.count('6.11.2') == 1, glob.iglob('PROJECT/**/6.11.2/', recursive=True))

否则,您总是可以使用os.scandir编写自己的目录遍历。


0
投票

如果我理解正确,就不想找到具有相同basename的目录,是吗?如果是,那么这应该可以解决问题:

import os
from collections import deque
from typing import List, Set


def scandir_only_dirs(path: str) -> List[str]:
    return [f.path for f in os.scandir(path) if f.is_dir()]


def scandir_no_same_basename(path: str) -> Set[str]:
    result = set()
    queue = deque(scandir_only_dirs(path))

    if not queue:
        return result

    visited_basenames = set()

    while queue:
        currdir = queue.popleft()
        basename = os.path.basename(currdir)
        if basename not in visited_basenames:
            result.add(currdir)
            queue.extendleft(scandir_only_dirs(currdir))
            visited_basenames.add(basename)

    return result

使用示例目录树,此函数返回:

{'.\\build',
 '.\\build\\sth1',
 '.\\build\\sth2',
 '.\\build\\sth2\\6.11.2',
 '.\\build\\sth2\\6.11.3',
 '.\\common'}

当然可以根据是否要考虑basename以外的其他部分来修改此算法,但是一般的想法是执行traversal并确定“访问”的标准。

编辑

在下面添加答案是因为我误解了这个问题:

def find_paths_to_dir(dir_basename: str, from_path: str=".") -> Set[str]:
    result = set()
    queue = deque(scandir_only_dirs(from_path))

    if not queue:
        return result

    while queue:
        currdir = queue.popleft()
        basename = os.path.basename(currdir)
        if basename == dir_basename:
            result.add(currdir)
        else:
            queue.extendleft(scandir_only_dirs(currdir))

    return result
© www.soinside.com 2019 - 2024. All rights reserved.