Как превратить список в вложенный dict в Python
Необходимо включить x:
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']
в псевдо-примере.
Поскольку это представляет файлы и папки, очевидно, на одном уровне (индекс массива) одноименные строки не могут повторяться.
Ответы
Ответ 1
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': {}}}
. Любой элемент, содержащий пустой словарь, является либо файлом, либо пустым каталогом.
Ответ 2
Предполагая, что {'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'])}}
Но, пожалуйста, не используйте его в реальном приложении:)
UPDATE:, который работает с произвольной глубиной:
>>> 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': {}}}}
Ответ 3
Это должно быть очень близко к тому, что вам нужно:
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']}}
Ответ 4
В вашей постановке проблемы существует логическая несогласованность. Если вы действительно хотите
['xyz/123/file.txt', 'abc/456/otherfile.txt']
чтобы изменить на
{'xyz': {'123': 'file.txt}, 'abc': {'456': 'otherfile.txt'}}
Затем вам нужно ответить, как в эту структуру данных будет вставлен путь "abc.txt" без ведущей папки. Будет ли ключ словаря верхнего уровня пустой строкой ''
?