从键中创建JavaScript对象,这些键在另一个对象中以点分隔

时间:2022-09-25 08:41:12

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

我有一个要求,我有一个像obj = {'a.b.c':d}的对象,我希望它转换为{a:{b:{c:d}}}

Is there any way I can achieve this in JavaScript?

有什么方法可以在JavaScript中实现这一点吗?

2 个解决方案

#1


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.

我不知道为什么你会有一个这样命名的对象,但是这个代码将为对象中的每个键执行操作。这在{'a':{'b'{'c':{{'d':'e'}}}}}等嵌套对象上无法正常工作。每次值为JavaScript对象时,您都必须重复for循环部分。

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.

我修改了代码,以便识别两个属性是否相同,如示例{'abc':22},'abcde':42。对不起,如果很难通过,但基本上generateNewObject方法是真正的肉它。它下面的两个函数只是辅助方法。

#2


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 ...

在处理/转换更复杂的数据结构时,Array.reduce主要是一个不错的选择。在考虑边缘情况时,一般解决给定问题的方法可能看起来类似于下一个提供的示例......

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));

#1


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.

我不知道为什么你会有一个这样命名的对象,但是这个代码将为对象中的每个键执行操作。这在{'a':{'b'{'c':{{'d':'e'}}}}}等嵌套对象上无法正常工作。每次值为JavaScript对象时,您都必须重复for循环部分。

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.

我修改了代码,以便识别两个属性是否相同,如示例{'abc':22},'abcde':42。对不起,如果很难通过,但基本上generateNewObject方法是真正的肉它。它下面的两个函数只是辅助方法。

#2


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 ...

在处理/转换更复杂的数据结构时,Array.reduce主要是一个不错的选择。在考虑边缘情况时,一般解决给定问题的方法可能看起来类似于下一个提供的示例......

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));