Make nested dictionary, unflatten
<p>I have a list of lists containing key and value like so:</p>

<pre><code>[
  ['mounts:device', '/dev/sda3'],
  ['mounts:fstype:[0]', 'ext1'],
  ['mounts:fstype:[1]', 'ext3']
]
</code></pre>

<p>Well I can easily change the list to this  </p>

<h1>(Lists arent seperated by ':')</h1>

<pre><code>[
  ['mounts:device', '/dev/sda3'],
  ['mounts:fstype[0]', 'ext1'],
  ['mounts:fstype[1]', 'ext3']
]
</code></pre>

<p>Whatever suits better for this problem:<br>
Problem is to create a dictionary:</p>

<pre><code>{
'mounts': {
    'device': '/dev/sda3',
    'fstype': [
        'ext1',
        'ext3'
    ]
}
</code></pre>

<p>It should also be possible to have lists in lists for example:</p>

<pre><code>['mounts:test:lala:fstype[0][0]', 'abc']
</code></pre>

<p>or</p>

<pre><code>['mounts:test:lala:fstype:[0]:[0]', 'abc']
</code></pre>

<p>This is what I have so far:</p>

<pre><code>def unflatten(pair_list):
    root = {}
    for pair in pair_list:
        context = root
        key_list = pair[0].split(':')
        key_list_last_item = key_list.pop()
        for key in key_list:
            if key not in context:
                context[key] = {}
            context = context[key]
        context[key_list_last_item] = pair[1]
    return root
</code></pre>

<p>Based on this answer <a href="http://stackoverflow.com/a/18648007/5413035">http://stackoverflow.com/a/18648007/5413035</a> but as requested I need recursivness and lists in the mix  </p>

<p>Thanks in advance</p>

<p>Here is a solution using a <strong>tree</strong> of <code>dict</code>:</p>

<pre><code>import collections

def tree():
    return collections.defaultdict(tree)


def unflatten(pair_list):
    root = tree()
    for mount, path in pair_list:
        parts = mount.split(":")
        curr = root
        for part in parts[:-1]:
            index = int(part[1:-1]) if part[0] == "[" else part
            curr = curr[index]
        part = parts[-1]
        index = int(part[1:-1]) if part[0] == "[" else part
        curr[index] = path
    return root
</code></pre>

<p>With the following input:</p>

<pre><code>pair_list = [
  ['mounts:device', '/dev/sda3'],
  ['mounts:fstype:[0]', 'ext1'],
  ['mounts:fstype:[1]', 'ext3'],
  ['mounts:test:lala:fstype:[0]:[0]', 'abc']
]
</code></pre>

<p>You'll get:</p>

<pre><code>{
    "mounts": {
        "fstype": {
            "0": "ext1",
            "1": "ext3"
        },
        "test": {
            "lala": {
                "fstype": {
                    "0": {
                        "0": "abc"
                    }
                }
            }
        },
        "device": "/dev/sda3"
    }
}
</code></pre>

<p>Then you can use the recursive function <code>make_list</code>bellow to turn the integer indexes in a <code>list</code>.</p>

<pre><code>def make_list(root):
    if isinstance(root, str):
        return root
    keys = list(root.keys())
    if all(isinstance(k, int) for k in keys):
        values = [None] * (max(keys) + 1)
        for k in keys:
            values[k] = make_list(root[k])
        return values
    else:
        return {k: make_list(v) for k, v in root.items()}
</code></pre>

<p>Here is the result with the <code>pair_list</code>:</p>

<pre><code>flat = unflatten(pair_list)
flat = make_list(flat)
</code></pre>

<p>You'll get:</p>

<pre><code>{'mounts': {'device': '/dev/sda3',
            'fstype': ['ext1', 'ext3'],
            'test': {'lala': {'fstype': [['abc']]}}}}
</code></pre>

<p>Is it fine?</p>

python python-3.x dictionary