比较Python中文件树的路径

时间:2015-02-24 17:35:26

标签: python tree iteration yaml traversal

我有一个带有文件夹树的YAML文件,如下所示:

---
- folder1
- folder2:
    - subfolder1:
        - deepfolder1
    - subolder2
- folder3
- folder4
...

我正在打开它:

with open(yaml_file) as f:
        tree = yaml.load(f)

我想将它与网址路径进行比较。

然后,我将分割网址元素以获取列表[folder1, folder2]

path_elements = parse.unquote_plus(request_path).split(sep)

request_path应该是文件夹的相对链接(不带斜杠)。

我想检查request_path是否位于YAML文件夹树中,然后返回例如True

但是我对如何以排序和“pythonic”方式比较两个对象感到很遗憾。

我提出的所有东西都有很多循环,感觉非常臃肿,既不聪明也不现代。

我正在使用Python 3.4,而且我对Python一般都是新手。

如果有更好的方法(YAML文件中的其他结构或比较这些的不同方法,欢迎提出每个建议!

1 个答案:

答案 0 :(得分:0)

您可能需要更多地解释一下您希望如何“比较”这两个对象,但我猜您的主要问题是您希望将该嵌套目录结构转换为平面列表路径即你想要这个嵌套结构:

- folder2:
    - subfolder1:
        - deepfolder1
        - deepfolder2

成为这些的平面列表:

folder2/subfolder1/deepfolder1
folder2/subfolder1/deepfolder2

这是“tree traversal”的一种形式。

这里有一个棘手的部分是通常树被表示为列表列表,但是你的YAML是混合关联数组(AKA dicts或哈希)和列表。所以这使代码变得更复杂。

这是您给出的数据的递归树遍历:

def traverse(t, prefix=None):
    prefix = prefix or []

    if len(t) == 0:
        raise StopIteration
    elif len(t) == 1:
        first, rest = t[0], []
    else:
        first, rest = t[0], t[1:]

    #walk first element
    if isinstance(first, str):
        #it's a single node
        yield prefix + [first]
    elif isinstance(first, list):
        #it's a list of nodes
        for element in first:
            for tmp in traverse(element, prefix=prefix):
                yield tmp
    elif isinstance(first, dict):
        #there's another level of nesting
        for sub in first:
            for tmp in traverse(first[sub], prefix=(prefix + [sub])):
                yield tmp

    #walk rest of elements recursively
    for element in traverse(rest, prefix=prefix):
        yield element

for expanded_path in traverse(tree):
    print(expanded_path)

如果您使用的是python 3.4,则可以使用yield from来清理“for tmp in ...: yield tmp”部分。 Full code here

当我在你的数据上运行时,我得到:

['folder1']
['folder2', 'subfolder1', 'deepfolder1']
['folder2', 'subolder2']
['folder3']
['folder4']

这些展开的路径采用与path_elements变量相同的格式,因此我们现在可以将它们相互比较。

您可能希望search SOpython recipes获得更好的树遍历算法,但我的效率可能不是最高的(有limit to python's recursion depth,因此您可能需要使用迭代正在制作中的版本。)

编辑:响应您的评论:“如果request_path在树结构中,则返回'True',您只需循环扩展路径并查看request_path是否与其匹配:

def compare(request_path, tree):
    path_elements = parse.unquote_plus(request_path).split(sep)
    for expanded_path in traverse(tree):
        if expanded_path == path_elements:
            return True
    return False

但它在某种程度上取决于request_path中的内容,是完整的URL(http://www.blah.com/foo/boo.txt)还是绝对URL(/foo/boo.txt)或相对URL(foo / boo.txt) )?如果是这样,您可能需要在比较它们之前清理路径。这一切都很容易做到(搜索SO以分割路径和URL),走树是一个复杂的部分。