【问题标题】:compare path to file tree in Python比较Python中文件树的路径
【发布时间】:2015-02-24 17:35:25
【问题描述】:

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

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

我打开它:

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

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

然后我拆分 URL 元素以获取列表 [folder1, folder2]

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

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

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

但是对于如何以排序和“pythonic”的方式比较两个对象,我有点迷茫。

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

我使用的是 Python 3.4,总的来说,我对 Python 非常陌生。

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

【问题讨论】:

    标签: python tree iteration yaml traversal


    【解决方案1】:

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

    - folder2:
        - subfolder1:
            - deepfolder1
            - deepfolder2
    

    要成为这些的平面列表:

    folder2/subfolder1/deepfolder1
    folder2/subfolder1/deepfolder2
    

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

    这里有一个棘手的部分是,通常树表示为列表的列表,但您的 YAML 混合了关联数组(AKA 字典或哈希)和列表。所以这会让代码稍微复杂一些。

    以下是您提供的数据的递归树遍历:

    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),遍历树是复杂的部分。

    【讨论】:

    • 谢谢!我为这个问题添加了一个更具体的目标:如果 request_path 在树结构中,则返回“True”。
    • 有了扩展路径列表后,这部分就很容易了。只需遍历所有扩展路径并将每个路径与 request_path 进行比较。我用这个信息编辑了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2014-02-05
    • 2014-02-28
    • 2014-06-09
    • 2021-11-29
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    相关资源
    最近更新 更多