0

I have a list of lists containing key and value like so:

[
  ['mounts:device', '/dev/sda3'],
  ['mounts:fstype:[0]', 'ext1'],
  ['mounts:fstype:[1]', 'ext3']
]

Well I can easily change the list to this

(Lists arent seperated by ':')

[
  ['mounts:device', '/dev/sda3'],
  ['mounts:fstype[0]', 'ext1'],
  ['mounts:fstype[1]', 'ext3']
]

Whatever suits better for this problem:
Problem is to create a dictionary:

{
'mounts': {
    'device': '/dev/sda3',
    'fstype': [
        'ext1',
        'ext3'
    ]
}

It should also be possible to have lists in lists for example:

['mounts:test:lala:fstype[0][0]', 'abc']

or

['mounts:test:lala:fstype:[0]:[0]', 'abc']

This is what I have so far:

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

Based on this answer https://stackoverflow.com/a/18648007/5413035 but as requested I need recursivness and lists in the mix

Thanks in advance

Community
  • 1
  • 1
Skeec
  • 125
  • 9
  • What's the question? See: [How do I ask a good question?](http://stackoverflow.com/help/how-to-ask) – Laurent LAPORTE Sep 14 '16 at 15:17
  • The question is how to achieve the unflatten to the nested dict the function below isnt working for lists – Skeec Sep 14 '16 at 15:18
  • What should the dictionary look like for the lists in lists example? Please [edit] your question and show us. – martineau Sep 14 '16 at 15:23
  • You have a list of "directives" that tell you how to construct a dictionary, it has nothing to do with flattening you should edit the title. – Seif Sep 14 '16 at 15:26

2 Answers2

1

Here is a solution using a tree of dict:

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

With the following input:

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

You'll get:

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

Then you can use the recursive function make_listbellow to turn the integer indexes in a list.

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

Here is the result with the pair_list:

flat = unflatten(pair_list)
flat = make_list(flat)

You'll get:

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

Is it fine?

Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
0
input1=[
  ['mounts:device', '/dev/sda3'],
  ['mounts:fstype:[0]', 'ext1'],
  ['mounts:fstype:[1]', 'ext3']
]
input2={x[1]:x[0].split(':')[1] for x in input1}
input3=['ext3', 'ext1', '/dev/sda3']
input4=['fstype', 'fstype', 'device']
res={}
for x,y in zip(input3, input4):
    res.setdefault(y,[]).append(x)
res1=res.keys()
res2=res.values()
res3=[x[0] for x in res2 if len(x)==1]+[x for x in res2 if len(x)>1]
result=dict(zip(res1,res3))

print result

Output :

{'device': '/dev/sda3', 'fstype': ['ext3', 'ext1']}
khelili miliana
  • 3,730
  • 2
  • 15
  • 28
  • Wrong output OP needs this: { 'mounts': { 'device': '/dev/sda3', 'fstype': [ 'ext1', 'ext3' ] } i.e. do not use lists when not required ('/dev/sda3') – Seif Sep 14 '16 at 15:27