JavaScript fusionando objetos por identificación

Resuelto Tam2 asked hace 11 años • 18 respuestas

¿Cuál es la forma correcta de fusionar dos matrices en Javascript?

Tengo dos matrices (por ejemplo):

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

Quiero poder terminar con algo como:

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

Donde las dos matrices se unen según el campo 'id' y simplemente se agregan datos adicionales.

Intenté usar _.unionpara hacer esto, pero simplemente sobrescribe los valores de la segunda matriz en la primera.

Tam2 avatar Oct 20 '13 23:10 Tam2
Aceptado

Solución corta ES6

const a3 = a1.map(t1 => ({...t1, ...a2.find(t2 => t2.id === t1.id)}))
Andreas Tzionis avatar May 08 '2020 01:05 Andreas Tzionis

Esto debería funcionar:

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

Esto supone que la identificación del segundo objeto en a1 debería ser 2 en lugar de "2".

Gruff Bunny avatar Oct 20 '2013 17:10 Gruff Bunny

Suponiendo que los ID son cadenas y el orden no importa, puede

  1. Crea una tabla hash.
  2. Itere ambas matrices y almacene los datos en la tabla hash, indexados por el ID. Si ya hay algunos datos con ese ID, actualícelos con Object.assign(ES6, se puede rellenar ).
  3. Obtenga una matriz con los valores del mapa 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];
});

En ECMAScript6, si los ID no son necesariamente cadenas, puede usar 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());
Oriol avatar May 19 '2015 20:05 Oriol

ES6 simplifica esto:

let merge = (obj1, obj2) => ({...obj1, ...obj2});

Tenga en cuenta que las claves repetidas se fusionarán, prevalecerá el valor del segundo objeto y se ignorará el valor repetido del primer objeto .

Ejemplo:

let obj1 = {id: 1, uniqueObj1Key: "uniqueKeyValueObj1", repeatedKey: "obj1Val"};
let obj2 = {id: 1, uniqueObj2Key: "uniqueKeyValueObj2", repeatedKey: "obj2Val"};

merge(obj1, obj2)
// {id: 1, uniqueObj1Key: "uniqueKeyValueObj1", repeatedKey: "obj2Val", uniqueObj2Key: "uniqueKeyValueObj2"}
merge(obj2, obj1)
// {id: 1, uniqueObj2Key: "uniqueKeyValueObj2", repeatedKey: "obj1Val", uniqueObj1Key: "uniqueKeyValueObj1"}

Solución completa (con Lodash , no Underscore )

var a1 = [{ id : 1, name : "test"}, { id : 2, name : "test2"}]
var a2 = [{ id : 1, count : "1"}, {id : 2, count : "2"}]
var merge = (obj1, obj2) => ({...obj1, ...obj2});
_.zipWith(a1, a2, merge)
(2) [{…}, {…}]
   0: {id: 1, name: "test", count: "1"}
   1: {id: 2, name: "test2", count: "2"}

Si tiene una serie de matrices para fusionar, puede hacerlo así:

var arrayOfArraysToMerge = [a1, a2, a3, a4]; //a3 and a4 are arrays like a1 and a2 but with different properties and same IDs.
_.zipWith(...arrayOfArraysToMerge, merge)
(2) [{…}, {…}]
   0: {id: 1, name: "test", count: "1", extra1: "val1", extra2: 1}
   1: {id: 2, name: "test2", count: "2", extra1: "val2", extra2: 2}
Alberto avatar Nov 28 '2018 10:11 Alberto