Как превратить список во вложенный dict в Python - PullRequest
11 голосов
/ 05 октября 2011

Нужно повернуть х:

X = [['A', 'B', 'C'], ['A', 'B', 'D']]

В Y:

Y = {'A': {'B': {'C','D'}}}

Более конкретно, мне нужно создать дерево папок и файлов из списка абсолютных путей, которое выглядит следующим образом:

paths = ['xyz/123/file.txt', 'abc/456/otherfile.txt']

где каждый путь равен split("/"), как указано в ['A', 'B', 'C'] в псевдо-примере.

Поскольку это представляет файлы и папки, очевидно, на одном уровне (индекс массива) одинаковые строки имен не могут повторяться.

Ответы [ 4 ]

24 голосов
/ 05 октября 2011
X = [['A', 'B', 'C'], ['A', 'B', 'D'],['W','X'],['W','Y','Z']]
d = {}

for path in X:
    current_level = d
    for part in path:
        if part not in current_level:
            current_level[part] = {}
        current_level = current_level[part]

Это оставляет нас с d, содержащим {'A': {'B': {'C': {}, 'D': {}}}, 'W': {'Y': {'Z': {}}, 'X': {}}}. Любой элемент, содержащий пустой словарь, является файлом или пустым каталогом.

6 голосов
/ 05 октября 2011

Если предположить, что {'C', 'D'} означает set(['C', 'D']), а ваша версия Python поддерживает dict comprehension и set comprehension, вот уродливое, но рабочее решение:

>>> tr = [[1, 2, 3], [1, 2, 4], [5, 6, 7]]
>>> {a[0]: {b[1]: {c[2] for c in [y for y in tr if y[1] == b[1]]} for b in [x for x in tr if x[0] == a[0]]} for a in tr}
{1: {2: set([3, 4])}, 5: {6: set([7])}}

Что касается вашего примера:

>>> X = [['A', 'B', 'C'], ['A', 'B', 'D']]
>>> {a[0]: {b[1]: {c[2] for c in [y for y in X if y[1] == b[1]]} for b in [x for x in X if x[0] == a[0]]} for a in X}
{'A': {'B': set(['C', 'D'])}}

Но, пожалуйста, не используйте его в реальных приложениях:)

ОБНОВЛЕНИЕ: вот тот, который работает с произвольной глубиной:

>>> def todict(lst, d=0):
...     print lst, d
...     if d > len(lst):
...         return {}
...     return {a[d]: todict([x for x in X if x[d] == a[d]], d+1) for a in lst}
...
>>> todict(X)
{'A': {'B': {'C': {}, 'D': {}}}}
1 голос
/ 05 октября 2011

Это должно быть довольно близко к тому, что вам нужно:

def path_to_dict(path):
    parts = path.split('/')

    def pack(parts):
        if len(parts) == 1:
            return parts
        elif len(parts):
            return {parts[0]: pack(parts[1:])}
        return parts

    return pack(parts)

if __name__ == '__main__':
    paths = ['xyz/123/file.txt', 'abc/456/otherfile.txt']
    for path in paths:
        print '%s -> %s' % (path, path_to_dict(path))

Результат:

xyz/123/file.txt -> {'xyz': {'123': ['file.txt']}}
abc/456/otherfile.txt -> {'abc': {'456': ['otherfile.txt']}}
0 голосов
/ 05 октября 2011

В вашей постановке проблемы есть логическое несоответствие.Если вы действительно хотите, чтобы ['xyz/123/file.txt', 'abc/456/otherfile.txt']

был изменен на {'xyz': {'123': 'file.txt}, 'abc': {'456': 'otherfile.txt'}}

Тогда вам нужно ответить, как путь 'abc.txt' без ведущей папки будет вставлен в эту структуру данных,Будет ли ключ словаря верхнего уровня пустой строкой ''?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...