0

I am looking for an elegant way to invert a JSON object's structure with variable depth like described below from a to b in Javascript ES6.

var a = {
    "cookie": {
        "CookieMessage": {
            "DE": "Nachricht",
            "EN": "Message"
        }
};



var b = {
        "DE": {
            "cookie": {
                "CookieMessage": "Nachricht"
            }
        },
        "EN": {
            "cookie": {
                "CookieMessage": "Message"
            }
        }
};

In Python i would do something like this, which is not very elegant as well:

def find(root=[], obj=None):
    ret = []
    for k, v in obj.items():
        if isinstance(v, dict):
            newroot = []
            newroot.extend(root)
            newroot.append(k)
            ret.extend(find(root=newroot, obj=v))
        else:
            copy = [k]
            copy.extend(root)
            ret.append((copy, v))
    return ret

def invert(obj=None):

    ret = {}
    f = find(obj=obj)
    for p, v in f:
        old = ret
        for n in p[:-1]:
            if n not in old:
                old[n] = {}
            old = old[n]
        old[p[-1]] = v

    return ret



a = {
    "cookie": {
        "CookieMessage": {
            "DE": "Nachricht",
            "EN": "Message"
        },
        "CookieSorte": {
            "DE": "Keks",
            "EN": "Coook"
        }
    }
}

print(invert(a))

Which results in:

{
    'DE': {
        'cookie': {
            'CookieSorte': 'Keks', 
            'CookieMessage': 'Nachricht'
        }
    }, 
    'EN': {
        'cookie': {
            'CookieSorte': 'Coook', 
            'CookieMessage': 'Message'
        }
    }
}
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Marco B.
  • 83
  • 1
  • 4
  • 2
    1. SO isn't a code-writing service; have you *tried* writing the ES6 version? What happened? 2. Your Python solution has this problem: https://stackoverflow.com/q/1132941/3001761 – jonrsharpe Jan 03 '18 at 10:28
  • Marco, I **highly** recommend against using "denglish" in your code, aka. mixing german and english. "CookieSorte" should be called "CookieType" or "CookieBrand" – MechMK1 Jan 03 '18 at 10:41

1 Answers1

0

You could first get the path to the value and then take the path and build a new object based on the changed path.

function invert(object) {
    var result = {};

    function setValue(target, path, value) {
        var last = path.pop();
        path.reduce((o, k) => o[k] = o[k] || {}, target)[last] = value;
    }

    function iter(o, p) {
        if (o && typeof o === 'object') {
            Object.keys(o).forEach(k => iter(o[k], [...p, k]));
            return;
        }
        p.unshift(p.pop());
        setValue(result, p, o);
    }

    iter(object, []);
    return result;
}

var source = { cookie: { CookieMessage: { DE: "Nachricht", EN: "Message" } } },
    target = invert(source);

console.log(target);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • This one does not exactly what i am looking for, because it inverts the whole tree, which is not what I want. The order of the nodes below the first level should be kept. Its more a split of the tree for the DE and the EN part. – Marco B. Jan 03 '18 at 12:35
  • @MarcoBartel, it should work now with the last key moved to the beginning. – Nina Scholz Jan 03 '18 at 12:39
  • Thank you very much, this is exactly what i am looking for. – Marco B. Jan 03 '18 at 13:08