2013-10-20 13 views
15

Qual è il modo corretto di unire due array in Javascript?JavaScript che unisce oggetti per ID

Ho due array (per esempio):

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

Voglio essere in grado di finire con qualcosa di simile:

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

Dove i due array vengono unite sulla base di il campo 'id' e i dati extra vengono semplicemente aggiunti.

ho cercato di utilizzare _.union per fare questo, ma sovrascrive semplicemente i valori della seconda matrice nel primo

+1

Quindi ciò che si vuole veramente è unire gli oggetti. – JJJ

+0

La sintassi non è valida. Hai un esempio legittimo? –

+0

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

risposta

29

Questo dovrebbe fare il trucco:

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

questo presuppone che l'id del secondo oggetto in A1 dovrebbe essere 2 piuttosto che "2"

+0

Perfetto , grazie – Tam2

+1

Questo non funzionerà se a2 ha più elementi nell'array di a1. – CAOakley

+1

@CAOakley - sì, lo sarà. Cosa ti fa pensare che non funzioni? –

0

È possibile scrivere una funzione fusione semplice oggetto come questo

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

successivo, è necessario fare utilizzare un doppio anello ad applicare al vostro structre dati

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 

è inoltre possibile utilizzare mergeObject come un semplice clone di troppo , passando un parametro come oggetto vuoto.

11

ID Supponendo sono stringhe e l'ordine non ha importanza , è possibile

  1. Creare una tabella hash.
  2. Iterare entrambi gli array e memorizzare i dati nella tabella hash, indicizzati dall'ID. Se sono già presenti alcuni dati con tale ID, aggiornarlo con Object.assign (ES6, può essere polyfilled).
  3. Ottieni un array con i valori della mappa 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]; 
}); 

In ECMAScript6, se gli ID non sono necessariamente le stringhe, è possibile utilizzare 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 versione.

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

Penso che sia una pratica comune nel linguaggio funzionale.

4

L'implementaiton lodash:

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

Il risultato:

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

Già ci sono molti grandi risposte, mi limiterò a aggiungere un altro uno che è da un vero e proprio problema di cui avevo bisogno per risolvere ieri .

Avevo una serie di messaggi con ID utente e un array di utenti contenente nomi di utenti e altri dettagli. È così che sono riuscito ad aggiungere dettagli utente ai messaggi.

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)