2013-10-20 64 views
15

在Javascript中合并两个数组的正确方法是什么?JavaScript通过id合并对象

我有两个阵列(例如):

var a1 = [{ id : 1, name : "test"}, { id : 2, name : "test2"}] 
var a2 = [{ id : 1, count : "1"}, {id : 2, count : "2"}] 

我希望能够与像落得:

var a3 = [{ id : 1, name : "test", count : "1"}, 
      { id : 2, name : "test2", count : "2"}] 

如果两个阵列是基于加入'id'字段和额外的数据只是被添加。

我试图用_.union要做到这一点,但它只是覆盖从第二数组中的值到第一个

+1

所以你真正想要做的就是合并对象。 – JJJ

+0

您的语法无效。你有一个合法的例子吗? –

+0

http://stackoverflow.com/questions/1584370/how-to-merge-two-arrays-in-javascript –

回答

29

这应该做的伎俩:

var mergedList = _.map(a1, function(item){ 
    return _.extend(item, _.findWhere(a2, { id: item.id })); 
}); 

这假定在A1中的第二个对象的ID应该是2,而不是“2”

+0

完美,谢谢 – Tam2

+1

如果a2在数组中的项数多于a1,这将不起作用。 – CAOakley

+1

@CAOakley - 是的。是什么让你觉得它不起作用? –

0

你可以写一个简单的对象合并功能类似这样的

function mergeObject(cake, icing) { 
    var icedCake = {}, ingredient; 
    for (ingredient in cake) 
     icedCake[ingredient] = cake[ingredient]; 
    for (ingredient in icing) 
     icedCake[ingredient] = icing[ingredient]; 
    return icedCake; 
} 

接下来,你需要做的使用双回路将它应用到你的数据结构法

var i, j, a3 = a1.slice(); 
for (i = 0; i < a2.length; ++i)    // for each item in a2 
    for (j = 0; i < a3.length; ++i)   // look at items in other array 
     if (a2[i]['id'] === a3[j]['id'])  // if matching id 
      a3[j] = mergeObject(a3[j], a2[i]); // merge 

您还可以使用mergeObject作为一个简单的克隆,太通过传递一个参数作为空对象。

11

假设ID是字符串和顺序并不重要,你可以

  1. 创建一个哈希表。
  2. 迭代两个数组并将数据存储在散列表中,并由ID进行索引。如果已经有一些带有该ID的数据,请使用Object.assign(ES6,可以是polyfilled)进行更新。
  3. 获取哈希映射值的数组。
var hash = Object.create(null); 
a1.concat(a2).forEach(function(obj) { 
    hash[obj.id] = Object.assign(hash[obj.id] || {}, obj); 
}); 
var a3 = Object.keys(hash).map(function(key) { 
    return hash[key]; 
}); 

在ECMAScript6,如果ID不一定是字符串,你可以使用Map

var hash = new Map(); 
a1.concat(a2).forEach(function(obj) { 
    hash.set(obj.id, Object.assign(hash.get(obj.id) || {}, obj)) 
}); 
var a3 = Array.from(hash.values()); 
3

reduce版本。

var a3 = a1.concat(a2).reduce((acc, x) => { 
    acc[x.id] = Object.assign(acc[x.id] || {}, x); 
    return acc; 
}, {}); 
_.values(a3); 

我认为这是在功能语言中的常见做法。

4

的lodash implementaiton:

var merged = _.map(a1, function(item) { 
    return _.assign(item, _.find(a2, ['id', item.id])); 
}); 

结果:

[ 
    { 
     "id":1, 
     "name":"test", 
     "count":"1" 
    }, 
    { 
     "id":2, 
     "name":"test2", 
     "count":"2" 
    } 
] 
1

已经有许多伟大的答案,我就再加一条是从一个真正的问题,我昨天需要解决。

我有一个包含用户id的消息数组,以及一个包含用户名和其他细节的用户数组。这是我设法将消息添加到用户的详细信息。

var messages = [{userId: 2, content: "Salam"}, {userId: 5, content: "Hello"},{userId: 4, content: "Moi"}]; 
var users = [{id: 2, name: "Grace"}, {id: 4, name: "Janetta"},{id: 5, name: "Sara"}]; 

var messagesWithUserNames = messages.map((msg)=> { 
    var haveEqualId = (user) => user.id === msg.userId 
    var userWithEqualId= users.find(haveEqualId) 
    return Object.assign({}, msg, userWithEqualId) 
}) 
console.log(messagesWithUserNames)