2015-02-24 6 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.

Но тогда я как бы теряюсь относительно того, как сравнивать два объекта в сортированном и «питоническом» способе.

Все, с чем я столкнулся, имеет много петель и чувствует себя чрезвычайно раздутым и не умным, не современным.

Я использую Python 3.4 и действительно новичок в Python в целом.

Если есть лучший способ сделать это (другие структуры в файле YAML или иного подхода к их сравнения, каждое предложение можно только приветствовать!

ответ

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 SO или python recipes для лучшего алгоритма обхода дерева, шахта не может быть наиболее эффективным (есть limit to python's recursion depth, так что вам, возможно, придется использовать итеративный вариант в производстве).

Edit: В ответ на ваш комментарий: «вернуть„True“, если 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 (foo/boo.txt)? Если это так, вам может понадобиться очистить пути, прежде чем сравнивать их. Это все довольно легко сделать (поиск SO для расщепления путей и URL-адресов), ходьба по дереву - сложная часть.

+0

спасибо до сих пор! Я добавил более конкретную цель на вопрос: return 'True', если request_path находится в древовидной структуре. – basbebe

+0

Эта часть проста после того, как у вас есть список расширенных путей. Просто зациклируйте все расширенные пути и сравните каждый из них с request_path. Я отредактировал свой ответ с этой информацией. –

Смежные вопросы