Python - Unflatten dict

I have this multidimensional dict:

a = {'a' : 'b', 'c' : {'d' : 'e'}}

And a simple function is written to smooth this dict:

def __flatten(self, dictionary, level = []):
    tmp_dict = {}
    for key, val in dictionary.items():
        if type(val) == dict:
            tmp_dict.update(self.__flatten(val, level + [key]))
        else:
            tmp_dict['.'.join(level + [key])] = val
    return tmp_dict

After calling this function with dict, aI get the result:

{'a' : 'b', 'c.d' : 'e'}

Now, with a few instructions on this flattened dict, I need to build a new, multidimensional dict from this flattened dict. Example:

>> unflatten({'a' : 0, 'c.d' : 1))
{'a' : 0, 'c' : {'d' : 1}}

The only problem I am facing is that I do not have a function unflatten:)
Can someone help with this? I do not know how to do that.

EDIT:

Another example:

{'a' : 'b', 'c.d.e.f.g.h.i.j.k.l.m.n.o.p.r.s.t.u.w' : 'z'}

Must be after unflatten:

{'a': 'b', 'c': {'d': {'e': {'f': {'g': {'h': {'i': {'j': {'k': {'l': {'m': {'n': {'o': {'p': {'r': {'s': {'t': {'u': {'w': 'z'}}}}}}}}}}}}}}}}}}}

And further:

{'a' : 'b', 'c.d' : 'z', 'c.e' : 1}

To:

{'a' : 'b', 'c' : {'d' : 'z', 'e' : 1}}

This greatly increases the complexity of the task, I know. That is why I had a problem with this and did not find any resolution in the clock.

+5
source share
4 answers
def unflatten(dictionary):
    resultDict = dict()
    for key, value in dictionary.iteritems():
        parts = key.split(".")
        d = resultDict
        for part in parts[:-1]:
            if part not in d:
                d[part] = dict()
            d = d[part]
        d[parts[-1]] = value
    return resultDict
+10
source
from collections import defaultdict
def unflatten(d):
    ret = defaultdict(dict)
    for k,v in d.items():
        k1,delim,k2 = k.partition('.')
        if delim:
            ret[k1].update({k2:v})
        else:
            ret[k1] = v
    return ret
+2

( , , , ):

def unflatten(d):
    result = {}
    for k,v in d.iteritems():
        if '.' in k:
            k1, k2 = k.split('.', 1)
            v = {k2: v}
            k = k1
        result[k] = v
    return result
+1

Here, one uses Python 3. 5+ features such as typing and restructuring assignments. Try tests on repl.it.

from typing import Any, Dict


def unflatten(
    d: Dict[str, Any], 
    base: Dict[str, Any] = None,
) -> Dict[str, Any]:
    """Convert any keys containing dotted paths to nested dicts

    >>> unflatten({'a': 12, 'b': 13, 'c': 14})  # no expansion
    {'a': 12, 'b': 13, 'c': 14}

    >>> unflatten({'a.b.c': 12})  # dotted path expansion
    {'a': {'b': {'c': 12}}}

    >>> unflatten({'a.b.c': 12, 'a': {'b.d': 13}})  # merging
    {'a': {'b': {'c': 12, 'd': 13}}}

    >>> unflatten({'a.b': 12, 'a': {'b': 13}})  # insertion-order overwrites
    {'a': {'b': 13}}

    >>> unflatten({'a': {}})  # insertion-order overwrites
    {'a': {}}
    """
    if base is None:
      base = {}

    for key, value in d.items():
        root = base

        ###
        # If a dotted path is encountered, create nested dicts for all but
        # the last level, then change root to that last level, and key to
        # the final key in the path.
        #
        # This allows one final setitem at the bottom of the loop.
        #
        if '.' in key:
            *parts, key = key.split('.')

            for part in parts:
                root.setdefault(part, {})
                root = root[part]

        if isinstance(value, dict):
            value = unflatten(value, root.get(key, {}))

        root[key] = value

    return base
0
source

All Articles