Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to turn a list into nested dict in Python

Need to turn x:

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

Into Y:

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

More specifically, I need to create a tree of folders and files from a list of absolute paths, which looks like this:

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

where, each path is split("/"), as per ['A', 'B', 'C'] in the pseudo example.

As this represents files and folders, obviously, on the same level (index of the array) same name strings can't repeat.

like image 887
Dmitry Grinberg Avatar asked Oct 04 '11 20:10

Dmitry Grinberg


3 Answers

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]

This leaves us with d containing {'A': {'B': {'C': {}, 'D': {}}}, 'W': {'Y': {'Z': {}}, 'X': {}}}. Any item containing an empty dictionary is either a file or an empty directory.

like image 78
Steven Rumbalski Avatar answered Oct 05 '22 13:10

Steven Rumbalski


Assuming that {'C', 'D'} means set(['C', 'D']) and your Python version supports dict comprehension and set comprehension, here's an ugly but working solution:

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

As for your example:

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

But please don't use it in a real-world application :)

UPDATE: here's one that works with arbitrary depths:

>>> 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': {}}}}
like image 22
Attila O. Avatar answered Oct 05 '22 13:10

Attila O.


There is a logical inconsistency in your problem statement. If you really want ['xyz/123/file.txt', 'abc/456/otherfile.txt']

to be changed to {'xyz': {'123': 'file.txt}, 'abc': {'456': 'otherfile.txt'}}

Then you have to answer how a path 'abc.txt' with no leading folder would be inserted into this data structure. Would the top-level dictionary key be the empty string ''?

like image 35
wberry Avatar answered Oct 05 '22 11:10

wberry