问题
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