[英]How to merge objects with the same properties into an Array?
我想将具有相同属性的 2 个对象合并到一个数组中。
以此为例:
object1 = {"id":1,
"name":name1,
"children":[{"id":2,"name":name2}]
};
object2 = {"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
};
object3 = {"id":1,
"name":name1,
"children":[{"id":6,"name":name6}]
};
var result = Object.assign(result,object1,object2,object3);
预期结果:
JSON.stringify([result]) =[
{"id":1,
"name":name1,
"children":[{"id":2,"name":name2},
{"id":6,"name":name6}]
},
{"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
}
]
实际结果:
JSON.stringify([result]) = [
{"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
}
]
似乎 Object.assign() 不是要走的路……因为它会覆盖,我不希望它覆盖,我希望它们合并。 有正确的方法吗?
通常, Array.prototype.reduce
为像这样的方法提供了一个很好的基础......
var obj1 = { "id": 1, "name": "name1", "children": [{ "id": 2, "name": "name2" }] }; var obj2 = { "id": 3, "name": "name3", "children": [{ "id": 4, "name": "name4" }] }; var obj3 = { "id": 1, "name": "name1", "children": [{ "id": 6, "name": "name6" }] }; // Expected result: [{ // "id": 1, // "name": name1, // "children": [ // { "id": 2, "name": "name2" }, // { "id": 6, "name": "name6" } // ] // }, { // "id": 3, // "name": "name3", // "children": [{"id": 4, "name": "name4" }] // }] function mergeEquallyLabeledTypes(collector, type) { var key = (type.name + '@' + type.id); // identity key. var store = collector.store; var storedType = store[key]; if (storedType) { // merge `children` of identically named types. storedType.children = storedType.children.concat(type.children); } else { store[key] = type; collector.list.push(type); } return collector; } var result = [obj1, obj2, obj3].reduce(mergeEquallyLabeledTypes, { store: {}, list: [] }).list; console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
编辑备注
在被告知需要处理嵌套模式的更改需求后,我会将我提供的第一个方法更改为通用解决方案。 这不会那么困难,因为在数据结构中存在一般重复的模式。 因此,我只需要使已经存在的 reducer 函数自递归。 在任何提供的列表上完成一个完整的归约循环后,将触发一个递归步骤......
var obj1 = { "id": 1, "name": "name1", "children": [{ "id": 2, "name": "name2", "children": [{ "id": 8, "name": "name8" }] }] }; var obj2 = { "id": 3, "name": "name3", "children": [{ "id": 4, "name": "name4", "children": [{ "id": 9, "name": "name9" }] }] }; var obj3 = { "id": 1, "name": "name1", "children": [{ "id": 6, "name": "name6", "children": [{ "id": 10, "name": "name10" }] }] }; var obj4 = { "id": 3, "name": "name3", "children": [{ "id": 4, "name": "name4", "children": [{ "id": 11, "name": "name11" }] }] }; function mergeEquallyLabeledTypesRecursively(collector, type, idx, list) { var key = (type.name + '@' + type.id); // identity key. var store = collector.store; var storedType = store[key]; if (storedType) { // merge `children` of identically named types. storedType.children = storedType.children.concat(type.children); } else { store[key] = type; collector.list.push(type); } // take repetitive data patterns into account ... if (idx >= (list.length - 1)) { collector.list.forEach(function (type) { // ... behave recursive, when appropriate. if (type.children) { type.children = type.children.reduce(mergeEquallyLabeledTypesRecursively, { store: {}, list: [] }).list; } }); } return collector; } var result = [obj1, obj2, obj3, obj4].reduce(mergeEquallyLabeledTypesRecursively, { store: {}, list: [] }).list; console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
这可能是你之后的事情,请注意它
不是递归
的,现在是递归的。 但是您的示例数据似乎并非如此。
const object1 = {"id":1, "name":"name1", "children":[{"id":2,"name":"name2"}] }; const object2 = {"id":3, "name":"name3", "children":[{"id":4,"name":"name4"}] }; const object3 = {"id":1, "name":"name1", "children":[ {"id":6,"name":"name6"}, {"id":7,"name":"name7"}, {"id":6,"name":"name6"} ] }; function merge(arr) { const idLinks = {}; const ret = []; arr.forEach((r) => { if (!idLinks[r.id]) idLinks[r.id] = []; idLinks[r.id].push(r); }); Object.keys(idLinks).forEach((k) => { const nn = idLinks[k]; const n = nn[0]; for (let l = 1; l < nn.length; l ++) { if (nn[l].children) { if (!n.children) n.children = []; n.children = n.children.concat(nn[l].children); } } if (n.children && n.children.length) n.children = merge(n.children); ret.push(n); }); return ret; } var result = merge([object1,object2,object3]); console.log(result);
以 es6 标准的函数式编程方式。 我假设 children 数组也包含重复项。 我将代码封闭在闭包中。
请参阅以下链接为什么我使用util
打印节点console.log()
中的所有对象
如何在 Node.js 的 console.log() 中获取完整的对象,而不是 '[Object]'?
(function() {
'use strict';
const util = require('util');
/** string constants */
const ID = 'id';
const CHILDREN = 'children';
/* Objects to modify */
const object1 = {
"id": 1,
"name": "name1",
"children": [
{ "id": 2, "name": "name2" },
{ "id": 5, "name": "name5" },
{ "id": 7, "name": "name7" }
]
};
const object2 = {
"id": 3,
"name": "name3",
"children": [
{ "id": 4, "name": "name4" }
]
};
const object3 = {
"id": 1,
"name": "name1",
"children": [
{ "id": 5, "name": "name5" },
{ "id": 6, "name": "name6" }
]
};
/**
* Concates the arrays
* @param { array } - a
* @param { array } - b
*/
const merge = (a, b) => {
return a.concat(b);
};
/**
* Removes Duplicates from the given array based on ID
* @param { array } - array to remove duplicates
* @return { array } - array without duplicates
*/
const removeDuplicates = (arr) => {
return arr.filter((obj, pos, arr) => {
return arr.map((m) => {
return m[ID];
}).indexOf(obj[ID]) === pos;
});
}
/**
* Groups items in array with particular key
* Currying technique
* @param { prop } - key to group
* @return { () => {} } - Method which in turn takes array as argument
*/
const groupBy = (prop) => (array) => {
return array.reduce((groups, item) => {
const val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
}
/**
* Object containing grouped-items by particuar key
*/
const grouped = groupBy(ID)([object1, object2, object3]);
/**
* Removing the duplicates of children
* Remember map also mutates the array of objects key's value
* but not data type
*/
Object.keys(grouped).map((key, position) => {
grouped[key].reduce((a, b) => {
a[CHILDREN] = removeDuplicates(a[CHILDREN].concat(b[CHILDREN]));
});
});
/**
* Desired final output
*/
const final = Object.keys(grouped)
.map((key) => removeDuplicates(grouped[key]))
.reduce(merge, []);
console.log(util.inspect(final, false, null))})();
/* There are two cases :
a) No duplicate children
b) Duplicate children either in (same object || different object|| both)
*/
/* =============== */
/* Case a) */
const util = require('util');
var object1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2" }]
};
var object2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4" }]
};
var object3 = {
"id": 1,
"name":"name1",
"children":[{"id":6,"name":"name6"}]
};
var arr = [object1,object2,object3];
var uniqueIds = [];
var filteredArray = [];
var uniqueId='';
arr.map((item,i,array)=>{
uniqueId =uniqueIds.indexOf(item.id);
uniqueId = uniqueId+1;
uniqueIds = [...uniqueIds,item.id];
if(!uniqueId){
filteredArray[i] = item;
}
if(uniqueId){
filteredArray[uniqueId-1]['children'] = [...(array[uniqueId-1].children),...(item.children)];
}
});
console.log(util.inspect(filteredArray,false,null));
/* ============================================
Case b)
Dealing with the worst case of having duplicate children in both same
and different objects
*/
object1 = {"id":1,
"name":'name1',
"children":[{"id":2,"name":'name2'},
{"id":2,"name":'name2'}]
};
object2 = {"id":3,
"name":'name3',
"children":[{"id":4,"name":'name4'}]
};
object3 = {"id":1,
"name":'name1',
"children":[{"id":6,"name":'name6'},
{"id":7,"name":'name7'},
{"id":2,"name":'name2'}]
};
arr = [object1,object2,object3];
uniqueIds = [];
uniqueId = '';
arr.map((item,i,array)=>{
uniqueId =uniqueIds.indexOf(item.id);
uniqueId = uniqueId+1;
uniqueIds = [...uniqueIds,item.id];
if(!uniqueId){
filteredArray[i] = item;
}
if(uniqueId){
filteredArray[uniqueId-1]['children'] = [...(array[uniqueId-1].children),...(item.children)];
}
/*Removing duplicate children entries*/
filteredArray[uniqueIds.indexOf(item.id)]['children'] = filteredArray[uniqueIds.indexOf(item.id)]['children']
.filter((elem, index, self) => self.findIndex((t) => {return t.id === elem.id}) === index)
})
console.log(util.inspect(filteredArray,false,null));
const object1 = {
"id":1,
"name":"name1",
"children":[{"id":2,"name":"name2"}]
};
const object2 = {
"id":3,
"name":"name3",
"children":[{"id":4,"name":"name4"}]
};
const object3 = {
"id":1,
"name":"name1",
"children":[{"id":6,"name":"name6"}]
};
var array = [object1,object2,object3];
var array2 = [object1,object2,object3];
function uniquearray(obj){
var result =[];
for(var i=0;i<array.length;i++){
if(obj.id == array[i].id){
result.push(array[i])
array.splice(i,1)
}
}
return result;
}
var arrayofuniarrays = []
for(var i=0;i<array2.length;i++){
arrayofuniarrays.push(uniquearray(array2[i]))
}
for(var i=0;i<arrayofuniarrays.length;i++){
for(var j=1;j<arrayofuniarrays[i].length; j++){
arrayofuniarrays[i][0].children.push(arrayofuniarrays[i][j].children)
arrayofuniarrays[i].splice(j,1)
}
}
var resul = arrayofuniarrays.reduce(function(a, b){return a.concat(b)},[])
console.log(resul)
这是如何执行此操作的草图示例。 它利用使用您的id
作为键的映射类型来确保每个项目只出现一次。 它将所有子项添加到基于 id 的数组中。
如果您需要对孩子强制执行相同的行为,您可以使用相同的技术。
我已将其拆分为多个迭代,以向您展示正在运行的各个部分。
通常,如果可以的话,避免创建需要压缩备份的对象会更有效。
const object1 = { "id": 1, "name": "name1", "children": [{ "id": 2, "name": "name2" }] }; const object2 = { "id": 3, "name": "name3", "children": [{ "id": 4, "name": "name4" }] }; const object3 = { "id": 1, "name":"name1", "children":[{"id":6,"name":"name6"}] }; const all = [object1, object2, object3]; // Use a map like a dictionary to enforce unique keys const mapped = {}; for (let obj of all) { if (!mapped[obj.id]) { mapped[obj.id] = obj; continue; } mapped[obj.id].children.push(obj.children); } console.log('Mapped ==> '+JSON.stringify(mapped)); // If you want to convert the mapped type to an array const result = []; for (let key in mapped) { result.push(mapped[key]); } console.log('Array ==> '+JSON.stringify(result));
在@Peter Seliger's answer here的基础上,我使用以下方法派生了将数组与深度嵌套的子级合并。
给定以下对象:
var obj1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2", children:[{ "id":8, "name": "name8" }] }]
};
var obj2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", children:[{ "id":9, "name": "name9" }] }]
};
var obj3 = {
"id": 1,
"name": "name1",
"children": [{ "id": 6, "name": "name6", children:[{ "id":10, "name": "name10" }] }]
};
var obj4 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", children:[{ "id":11, "name": "name11" }] }]
};
首先我们合并父母
function mergeEquallyLabeledTypes(collector, type) {
var key = (type.name + '@' + type.id); // identity key.
var store = collector.store;
var storedType = store[key];
if (storedType) { // merge `children` of identically named types.
if(storedType.children)
storedType.children = storedType.children.concat(type.children);
} else {
store[key] = type;
collector.list.push(type);
}
return collector;
}
var result = [obj1, obj2, obj3, obj4].reduce(mergeEquallyLabeledTypes, {
store: {},
list: []
}).list;
然后我们合并孩子和子孩子(如果有的话)。
for(let i=0; i<result.length; i++){
var children = result[i].children;
if(children){
var reducedChildren = children.reduce(mergeEquallyLabeledTypes, {store: {}, list: []}).list;
for(let j=0; j<reducedChildren.length; j++){
var subchildren = reducedChildren[j].children;
if(subchildren){
var reducedSubchildren = subchildren.reduce(mergeEquallyLabeledTypes, {store: {}, list: []}).list;
reducedChildren[j].children = reducedSubchildren;
}
}
result[i].children = reducedChildren;
}
}
最后结果将是我将解析到我的网站中的内容。
console.log('result : ', result);
我能够得到预期的结果。
// result: [{
// "id": 1,
// "name": name1,
// "children": [
// { "id": 2, "name": "name2", children:[{ "id":8, "name": "name8" }] },
// { "id": 6, "name": "name6", children:[{ "id":10, "name": "name10" }] }
// ]
// }, {
// "id": 3,
// "name": "name3",
// "children": [{"id": 4, "name": "name4", children:[
// { "id":9, "name": "name9" },
// { "id":11, "name": "name11" }
// ]
// }
// ]
// }]
但是,这可能不太有效,因为如果我的树嵌套更多级别,我需要继续添加子/子子合并方法。 (例如 subsubchildren、subsubsubchildren 等等...)
有没有更有效的方法来做到这一点?
const object1 = {
id:1,
name:'a',
}
const object2 = {
id:3,
name:'b',
}
const object3 = {
id:1,
name:'c',
}
const originArr = [object1, object2, object3]
const idArr = [object1.id, object2.id, object3.id]
const newIdArr = []
for (let id of idArr) {
if (newIdArr.indexOf(id)) newIdArr.push(id)
}
const result = newIdArr.map(id => {
let names = []
for (obj of originArr) {
if (id === obj.id) names.push(obj.name)
}
return { id, names }
})
console.log(result)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.