Cómo convertir una lista en dict nested en Python

Necesito girar x:

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

En Y:

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

Más específicamente, necesito crear un árbol de carpetas y archivos a partir de una lista de rutas absolutas, que se ve así:

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

donde, cada ruta se split("/") , según ['A', 'B', 'C'] en el pseudo ejemplo.

Como esto representa archivos y carpetas, obviamente, en el mismo nivel (índice de la matriz) no se pueden repetir las mismas cadenas de nombre.

 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] 

Esto nos deja con d que contiene {'A': {'B': {'C': {}, 'D': {}}}, 'W': {'Y': {'Z': {}}, 'X': {}}} . Cualquier elemento que contenga un diccionario vacío es un archivo o un directorio vacío.

Suponiendo que {'C', 'D'} significa set(['C', 'D']) y su versión de Python admite la dict comprehension y la set comprehension , aquí hay una solución fea pero funcional:

 >>> 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])}} 

En cuanto a tu ejemplo:

 >>> 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'])}} 

Pero, por favor, no lo use en una aplicación del mundo real 🙂

ACTUALIZACIÓN: aquí hay uno que trabaja con profundidades arbitrarias:

 >>> 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': {}}}} 

Esto debería estar bastante cerca de lo que necesitas:

 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)) 

Resultados en:

 xyz/123/file.txt -> {'xyz': {'123': ['file.txt']}} abc/456/otherfile.txt -> {'abc': {'456': ['otherfile.txt']}} 

Hay una inconsistencia lógica en su statement del problema. Si realmente desea ['xyz/123/file.txt', 'abc/456/otherfile.txt']

para cambiar a {'xyz': {'123': 'file.txt}, 'abc': {'456': 'otherfile.txt'}}

Luego, debe responder cómo se insertaría una ruta ‘abc.txt’ sin una carpeta inicial en esta estructura de datos. ¿La clave del diccionario de nivel superior sería la cadena vacía '' ?