2015-02-24 76 views
1

我有一個文件夾樹看起來像這樣YAML文件:比較文件路徑樹在Python

--- 
- 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文件或不同的方法來比較這些其他的結構,每一個建議是歡迎!

回答

0

您可能需要解釋一點關於你如何期待對「比較」的兩個對象,但我要去猜測,你的主要問題是,你要打開的是嵌套的目錄結構爲路徑的平面列表例如,你希望這個嵌套結構:

- 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是樹結構中」,你只需要循環擴展的路徑,看看是否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(富/ boo.txt)?如果是這樣,您可能需要在比較之前清理路徑。儘管這樣做很容易(搜索SO用於分割路徑和URL),但走樹是複雜的部分。

+0

感謝到目前爲止!我爲這個問題添加了一個更具體的目標:如果request_path在樹結構中,則返回'True'。 – basbebe 2015-02-24 19:38:04

+0

一旦您擁有擴展路徑列表,該部分就很容易。只需循環遍歷所有擴展路徑,並將每個路徑與request_path進行比較。我用這個信息編輯了我的答案。 – 2015-02-24 19:48:29