简体   繁体   English

如何将具有相同属性的对象合并到一个数组中?

[英]How to merge objects with the same properties into an Array?

I would like to merge 2 objects with the same properties into an Array.我想将具有相同属性的 2 个对象合并到一个数组中。

Take this for an example:以此为例:

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

Expected result:预期结果:

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

Actual result:实际结果:

JSON.stringify([result]) = [
                            {"id":3,
                             "name":name3,
                             "children":[{"id":4,"name":name4}]
                            }
                           ]

Seems like Object.assign() isn't the way to go... as it will overwrite, I do not want it to overwrite, I want them to merge instead.似乎 Object.assign() 不是要走的路……因为它会覆盖,我不希望它覆盖,我希望它们合并。 Is there a right way to do this?有正确的方法吗?

As so often, Array.prototype.reduce provides a good base for an approach like eg this one ...通常, 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; }

Edit Note编辑备注

After having been informed about changed requirements, that need to deal with a nested pattern, I will change my first provided approach into a generic solution.在被告知需要处理嵌套模式的更改需求后,我会将我提供的第一个方法更改为通用解决方案。 It will be not that difficult since there is a generically repeated pattern within the data structure.这不会那么困难,因为在数据结构中存在一般重复的模式。 Thus I just need to make the already existing reducer function self recursive.因此,我只需要使已经存在的 reducer 函数自递归。 A recursion step will be triggered after having finished a complete reducing cycle on any provided list ...在任何提供的列表上完成一个完整的归约循环后,将触发一个递归步骤......

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

This might be what your after, please note it's not recursive now recursive.这可能是你之后的事情,请注意它 不是递归 的,现在是递归的。 But your example data doesn't appear to be anyway.但是您的示例数据似乎并非如此。

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

In functional programming way with es6 standards.以 es6 标准的函数式编程方式。 I am assuming children array also contains duplicates.我假设 children 数组也包含重复项。 I enclosed the code in closures.我将代码封闭在闭包中。

See the following link why I used util to print all the object in node console.log()请参阅以下链接为什么我使用util打印节点console.log()中的所有对象

How can I get the full object in Node.js's console.log(), rather than '[Object]'? 如何在 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)

Here is a sketch example of how to do this.这是如何执行此操作的草图示例。 It leverages a mapped type using your id as a key to ensure each item only appears once.它利用使用您的id作为键的映射类型来确保每个项目只出现一次。 It adds all of the children to an array based on the id.它将所有子项添加到基于 id 的数组中。

If you needed to enforce the same behaviour on the children, you could use the same technique.如果您需要对孩子强制执行相同的行为,您可以使用相同的技术。

I have split this into multiple iterations to show you the individual parts in play.我已将其拆分为多个迭代,以向您展示正在运行的各个部分。

Usually, it is more efficient to avoid creating objects that need to be zipped back up if you can.通常,如果可以的话,避免创建需要压缩备份的对象会更有效。

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

Building on @Peter Seliger's answer here , I derived with the following method to merge arrays with deeply nested children.在@Peter Seliger's answer here的基础上,我使用以下方法派生了将数组与深度嵌套的子级合并。

Given the following objects:给定以下对象:

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" }] }]
};    

First we merge the parents首先我们合并父母

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;

Then we merge the children and subchildren if any.然后我们合并孩子和子孩子(如果有的话)。

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

Finally the result will be what I'll parse into my website.最后结果将是我将解析到我的网站中的内容。

console.log('result : ', result);

I am able to get the expected 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" }
    //                                            ]  
    //               }
    //    ]
    // }]

However, this might not be too efficient as I'll need to keep adding on to the merging of children/subchildren method if my tree get nested with more levels.但是,这可能不太有效,因为如果我的树嵌套更多级别,我需要继续添加子/子子合并方法。 (eg subsubchildren, subsubsubchildren and so on...) (例如 subsubchildren、subsubsubchildren 等等...)

Is there any more efficient way to do this?有没有更有效的方法来做到这一点?

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.

相关问题 如何将具有相同属性的对象合并到一个数组中? - How to merge objects with the same properties into a single Array? 将具有相同属性的两个对象的方法合并到每个属性的数组中 - Merge methods of two objects with same properties into array for each property 对象数组(JavaScript)合并并使用相同的键添加属性 - Array of Objects (JavaScript) merge and add properties with same key 如果 javascript 中的 id 相同,如何合并数组中所有属性的两个对象? - How to merge two objects of all properties in an array if it has same id in javascript? 如何使用lodash合并/连接对象数组中相同对象属性的值? - How to merge/concatenate values of same object properties in an array of objects using lodash? 合并对象数组的相同属性并在该 object 数组中创建 object 数组以获得不同的属性 - merge same properties of array of objects and create array of object within that array of object for different properties 如何基于相同的值合并对象数组? - How to merge Array of Objects based on the same value? 如何合并具有相同键的对象数组 - How to merge array of objects with same key 如何合并对象数组仅将属性保留在第一个数组中 - How to merge an array of objects keep only properties in the first array 如何将对象数组中的某些属性合并到另一个数组中? - How to merge some properties in array of objects into another array?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM