0

I have a requirement where I have an object like obj={ 'a.b.c' : d } and I would like it to get converted to {a:{b:{c:d}}}

Is there any way I can achieve this in JavaScript?

5
  • There is no such object as {a.b.c:d}. That is invalid syntax. Commented Aug 4, 2016 at 13:54
  • @torazaburo It's perfectly valid if you create an empty object and set properties using the obj[key] syntax, although I don't see why you would. It also works if you set the key as a string during object declaration. Commented Aug 4, 2016 at 14:01
  • @kag359six Then the OP should fix his question to set it as a string, as it stands now, it is invalid syntax. Commented Aug 4, 2016 at 14:03
  • @torazaburo You are certainly correct, I revised his question, which is currently pending review. Commented Aug 4, 2016 at 14:05
  • Possible duplicate of Looking for an FP algorithm to compose objects from dot-separated strings Commented Aug 4, 2016 at 16:42

2 Answers 2

0

Here's a solution (EDITED: code is more complex than before but it gives the result you want, let me know if something doesn't work):

var obj = {
    'a.b.c': 22,
    'a.b.d.e': 42
}

var newObj = {};

for (var key in obj) {

    if (obj.hasOwnProperty(key)) {

        var keyList = key.split('.');
        newObj = generateNewObject(keyList, keyList.length - 1, newObj, obj[key]);

    }

}

console.log(newObj);

function generateNewObject(keys, index, existingObj, value) {

    if (index < 0) {
        return value;
    }

    var lastKey = keys[index--];
    var existingProperty = getProperty(existingObj, lastKey);

    if (existingProperty != null && !objectsAreEqual(existingProperty, value)) {

        var valueKey = keys[index + 2];
        existingProperty[lastKey][valueKey] = value[valueKey];
        value = existingProperty;


    } else {

        var subObj = {};
        subObj[lastKey] = value;
        value = subObj;
    }

    return generateNewObject(keys, index, existingObj, value);

}

function objectsAreEqual(obj1, obj2) {

    for (var key in obj1) {

        if (obj1.hasOwnProperty(key)) {

            var prop = getProperty(obj2, key);
            if (prop == null) {
                return false;
            }

        }

    }

    return true;

}

function getProperty(obj, keyDesired) {

    for (var key in obj) {

        if (obj.hasOwnProperty(key)) {

            if (key === keyDesired) {

                return obj;

            } else {

                var prop = getProperty(obj[key], keyDesired);

                if (prop != null) {
                    return prop;
                }

            }

        }

    }

    return null;

}

I don't know why you would have an object named that way, but this code will do the trick for each key in an object. This will not work correctly on nested objects such as {'a' : { 'b' { 'c' : {{'d' : 'e'}}}}}. You would have to repeat the for-loop part each time the value is a JavaScript object.

EDIT

I modified the code so it recognizes when two properties are the same such as the example { 'a.b.c' : 22 }, 'a.b.c.d.e' : 42. Sorry if it is hard to go through, but basically the generateNewObject method is the real meat of it. The two functions below it are just helper methods.

Sign up to request clarification or add additional context in comments.

5 Comments

Wouldn't he expect {'a.b.c': 22, 'a.b.d': 42} to yield {a: {b: {c: 22, d: 42} } }?
Yes I want what you are saying torazaburo
@kag359six Thanks for the answer .It was helpful.but if what is suggested by torazaburo is possible then it would be perfect
@user1835326 check out my revisions and let me know if that works for you
@user1835326 Great, please accept this as the right answer :)
0

Array.reduce mostly is a good choice when it comes to handling/transforming of more complex data structures. An approach that solves the given problem generically whilst taking edge cases into account then might look similar to the next provided example ...

var
    d   = 'd',
    q   = 'q',

    obj = {
        'i.k.l.m.n.o.p' : q,
        'a.b.c'         : d,
        'foo'           : 'bar',
        ''              : 'empty'
    };

function parseIntoNestedTypes(type) {
    return Object.keys(type).reduce(function (collector, integralKey) {

        var
            nestedType          = collector.target,
            fragmentedKeyList   = integralKey.split('.'),
            nestedTypeRootKey   = fragmentedKeyList.shift(),
            nestedTypeEndValue  = collector.source[integralKey];

        if (fragmentedKeyList.length === 0) {

            nestedType[nestedTypeRootKey] = nestedTypeEndValue;
        } else {
            nestedType[nestedTypeRootKey] = fragmentedKeyList.reduce(function (collector, key, idx, list) {

                var
                    partialType = collector.partialType || collector.type;

                if (idx < (list.length - 1)) {

                    partialType[key] = {};
                } else {
                    partialType[key] = collector.value;
                }
                collector.partialType = partialType[key];

                return collector;

            }, {

                value : nestedTypeEndValue,
                type  : {}

            }).type;
        }
        return collector;

    }, {

        source: type,
        target: {}

    }).target;
}

console.log('parseIntoNestedTypes :: type', JSON.stringify(obj));
console.log('parseIntoNestedTypes :: nestedType', JSON.stringify(parseIntoNestedTypes(obj)));

console.log('parseIntoNestedTypes :: type, nestedType : ', obj, parseIntoNestedTypes(obj));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.