Javascript merge/reduce same multi dimensional objects

試著忘記壹切 提交于 2019-12-10 17:50:07

问题


based on my question: https://stackoverflow.com/a/40661953/2392461, i open a new question with sample data.

I want to merge/reduce this:

var array = [{
  'key1': {
    'key11': 0,
    'key12': 1
  },
  'key2': 0,
  'key3': {
    'key31': [1, 2],
    'key32': {
        'key321': 3,
        'key322': [1, 2]
    }
  },
  'key4': 'test'
  }, {
  'key1': {
    'key11': 1,
    'key12': 9
  },
  'key2': 2,
  'key3': {
    'key31': [4, 3],
    'key32': {
        'key321': 6,
        'key322': [8, 9]
    }
  },
  'key4': 'test'
  }, {
  'key1': {
    'key11': 3,
    'key12': 4
  },
  'key2': 7,
  'key3': {
    'key31': [3, 2],
    'key32': {
        'key321': 6,
        'key322': [7, 8]
    }
  },
  'key4': 'test'
}];

to this:

{
  'key1': {
    'key11': [0, 1, 3],
    'key12': [1, 9, 4]
  },
  'key2': [0, 2, 7],
  'key3': {
    'key31': [[1, 2], [4, 3], [3, 2]],
    'key32': {
        'key321': [3, 6, 6],
        'key322': [[1, 2], [8, 9], [7, 8]]
    }
  },
  'key4': 'test'
}

the reduce function (https://stackoverflow.com/a/40668315/2392461) from @stasovlas with lodash looks good but i need to go deeper in the object.

_.reduce(data, function(result, item) {
    var added = _.find(result, {
        key4: item.key4
    });
    if (_.isObject(added)) {
        //!! better to merge with new object and add result to array again to avoid mutable
        added = _.mergeWith(added, item, function(addedVal, itemVal, key) {
            if (key === 'key4') {
                return addedVal;
            }
            return _.concat(addedVal, itemVal);
        });
        return result;
    }
    return _.concat(result, item);
}, []);

result is here a merged object only in layer 1 of the object.

[ { key1: [ [Object], [Object], [Object] ],
    key2: [ 0, 2, 7 ],
    key3: [ [Object], [Object], [Object] ],
    key4: 1 } ]

i have no idea how to get my result. i think i have to iterate each object n times. n is the depth of the object.

is this the right way or is it easier than i think?

greetings mok


回答1:


You could merge each level by iterating the entries of the source object and create either a new object or an array for adding the result. Proceed with child objects.

key4 gets a special treatment.

function merge(target, source) {
    var singleKey = 'key4';
    Object.entries(source).forEach(([key, value]) => {
        if (value && typeof value === 'object' && !Array.isArray(value)) {
            merge(target[key] = target[key] || {}, value);
            return;
        }
        if (key === singleKey) {
            target[key] = value;
            return;
        }
        target[key] = target[key] || [];
        target[key].push(value);
    });
    return target;
}

var array = [{ key1: { key11: 0, key12: 1 }, key2: 0, key3: { key31: [1, 2], key32: { key321: 3, key322: [1, 2] } }, key4: "test" }, { key1: { key11: 1, key12: 9 }, key2: 2, key3: { key31: [4, 3], key32: { key321: 6, key322: [8, 9] } }, key4: "test" }, { key1: { key11: 3, key12: 4 }, key2: 7, key3: { key31: [3, 2], key32: { key321: 6, key322: [7, 8] } }, key4: "test" }],
    result = array.reduce(merge, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }



回答2:


I have made a few improvements, it is more flexible for any kind of this problem.

function merge(target, source) {
    var fixedKeys = ['key1', 'key2', 'keyn'];

    Object.entries(source).forEach(([key, value]) => {
        if (value && value.toString() === '[object Object]') {
            merge(target[key] = target[key] || {}, value);
            return;
        }
        if (value && Array.isArray(value)) {
            merge(target[key] = target[key] || [], value);
            return;
        }
        if (fixedKeys.indexOf(key) !== -1) {
            target[key] = value;
            return;
        }
        target[key] = target[key] || [];
        target[key].push(value);
    });
    return target;
}

Now u can merge/reduce also deeper values/arrays/object, there is no converting from JS Arrays to Objects or otherwise and it is JSON.stringify compatible. You can set an Array of keys which should occur only once.

hope this is helping not only me :)



来源:https://stackoverflow.com/questions/51400554/javascript-merge-reduce-same-multi-dimensional-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!