JavaScript mesclando objects por id

Qual é a maneira correta de mesclar duas matrizes em JavaScript?

Eu tenho dois arrays (por exemplo):

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

Eu quero ser capaz de acabar com algo como:

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

Onde os dois arrays estão sendo unidos com base no campo ‘id’ e dados extras estão sendo adicionados.

Eu tentei usar o _.union para fazer isso, mas ele simplesmente sobrescreve os valores do segundo array no primeiro.

Isso deve fazer o truque:

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

Isso pressupõe que o id do segundo object em a1 deve ser 2 em vez de “2”

Assumindo que IDs são strings e a ordem não importa, você pode

  1. Crie uma tabela de hash.
  2. Iterar as matrizes e armazenar os dados na tabela de hash, indexados pelo ID. Se já houver alguns dados com esse ID, atualize-o com Object.assign (ES6, pode ser polyfilled ).
  3. Obter uma matriz com os valores do mapa de hash.
 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]; }); 

No ECMAScript6, se os IDs não forem necessariamente strings, você poderá usar o 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()); 

reduzir a versão.

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

Eu acho que é uma prática comum em linguagem funcional.

A implementação lodash:

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

O resultado:

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

Já existem muitas respostas ótimas, vou apenas adicionar outra que é de um problema real que eu precisava resolver ontem.

Eu tinha uma matriz de mensagens com IDs de usuário e uma matriz de usuários contendo nomes de usuários e outros detalhes. Foi assim que consegui adicionar detalhes do usuário às mensagens.

 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) 

Você pode escrever uma function simples de mesclagem de objects como esta

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

Em seguida, você precisa usar um loop duplo para aplicá-lo à sua estrutura de dados

 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 

Você também pode usar mergeObject como um simples clone, passando um parâmetro como um object vazio.

Isso deve fazer o truque em es6 e é funcional:

 const a1 = [{ id: 1, name: 'test' }, { id: 2, name: 'test2' }]; const a2 = [{ id: 1, count: '1' }, { id: 2, count: '2' }]; const mergeArray = (source, merge, by) => source.map(item => ({ ...item, ...(merge.find(i => i[by] === item[by]) || {}), })); console.log(mergeArray(a1, a2, 'id')); // > ​​​​​[{ id: 1, name: 'test', count: '1' }, { id: 2, name: 'test2', count: '2' }] 

Isso também pressupõe que o id do segundo object em a1 deve ser 2 em vez de “2”.