How to convert a list of lists into a multi-level nested dictionary?

I want to convert a list of lists to multi-level nested dictionaries like so:

x = [[1, 2, 3, 4],
     [1, 2, 4, 5],
     [5, 6, 7, 8]]


print(f(x))
## {
##  1: {2: {3: 4},
##         {4: 5}},
##  5: {6: {7: 8}}    
## }

The list inside can be arbitrary long. Any ideas would be very helpful. For any set of nested keys, there is only one unique value possible. Thank you. So, the list mentioned below does not occur:

x = [[1,2,3,4],
     [1,2,3,5]]

I tried the function below but it throws an AttributeError: ‘int’ object has no attribute ‘keys’.

Also, it updates incorrectly as mentioned below, so not very helpful.

def listoflists_dict(listformat):
    a = dict()
    cur = a
    for inner_list in listformat:
        for i, ele in enumerate(inner_list):
            print(a)
            if (ele not in cur.keys()) and (i < len(inner_list) - 1):
                cur[ele] = dict()
                cur = cur[ele]
            elif (ele not in cur.keys()) and (i == len(inner_list) - 1):
                cur[ele] = inner_list[-1]
            else:
                cur = cur[ele]
    
    return a

listformat = [[1, 2, 3, 4],
     [1, 2, 4, 5],
     [5, 6, 7, 8]]

listoflists_dict(listformat)

## {}
## {1: {}}
## {1: {2: {}}}
## {1: {2: {3: {}}}}
## {1: {2: {3: {4: 4}}}}
## {1: {2: {3: {4: 4, 1: {}}}}}
## {1: {2: {3: {4: 4, 1: {2: {}}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {}}}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {5: 5}}}}}}}
## {1: {2: {3: {4: 4, 1: {2: {4: {5: 5}}}}}}}

>Solution :

Good idea, with two major problems:

  • You don’t reset cur for each ele. Moving cur = a one line down will fix this problem.
  • The element that needs special handling is len(inner_list) - 2, not len(inner_list) - 1. You must not process len(inner_list) - 1, so a break is useful.

With this, your code becomes:

def listoflists_dict(listformat):
    a = dict()
    for inner_list in listformat:
        cur = a
        for i, ele in enumerate(inner_list):
            if (ele not in cur.keys()) and (i < len(inner_list) - 2):
                cur[ele] = dict()
                cur = cur[ele]
            elif (ele not in cur.keys()) and (i == len(inner_list) - 2):
                cur[ele] = inner_list[-1]
                break
            else:
                cur = cur[ele]
    
    return a

Now, several non-essential comments:

  • ele not in cur.keys() will sequentially test each key in cur, since cur.keys() is a generator; ele not in cur will directly test if a key is present in a dict, and should therefore be preferred
  • Similarly, {}, as a literal is faster than dict(), which must invoke a function
  • It is easier to tear off the last two elements, rather than having to check for them

With that, here is a faster and sleeker version:

def listoflists_dict(listformat):
    a = {}
    for *path, key, val in listformat:
        cur = a
        for ele in path:
            if ele not in cur:
                cur[ele] = {}
            cur = cur[ele]
        cur[key] = val
    return a

Leave a Reply