web-dev-qa-db-fra.com

Combinez les tableaux JSON par clé, javascript

Je dois combiner deux tableaux JSON, fournis par deux services de repos. Les entrées avec le même "id" vont de pair.

json1 = [{id:1,name:'aaa'},
     {id:5,name:'ccc'},
     {id:3,name:'bbb'}
   ];

 json2 = [{id:3,parameter1:'x', parameter2:'y', parameter3:'z'},
     {id:1,parameter1:'u', parameter2:'v', parameter3:'w'},
     {id:5,parameter1:'q', parameter2:'w', parameter3:'e'}
    ];

J'ai besoin d'un tableau json combiné/copié/cloné en javascript de la manière suivante (mon modèle en angular2):

json3 = [{id:3,name:'bbb',parameter1:'x', parameter2:'y',   parameter3:'z'},
     {id:1,name:'aaa', parameter1:'u', parameter2:'v', parameter3:'w'},
     {id:5,name:'ccc', parameter1:'q', parameter2:'w', parameter3:'e'}
    ];

Y a-t-il un moyen de les combiner? Les noms de paramètre ne sont pas définis exactement et il doit fonctionner avec des vecteurs de paramètre variables.

Je l'ai essayé avec mixte pour chaque boucles. Cela me semble très moche.

10
user2083142

Si vous voulez l'écrire de manière à pouvoir prendre n'importe quel nombre de tableaux, pas seulement 2, vous pouvez utiliser arguments et faire quelque chose comme ça:

var json1 = [{id:1,name:'aaa'},{id:5,name:'ccc'},{id:3,name:'bbb'}];

var json2 = [{id:3,parameter1:'x', parameter2:'y', parameter3:'z'},
 {id:1,parameter1:'u', parameter2:'v', parameter3:'w'},
 {id:5,parameter1:'q', parameter2:'w', parameter3:'e'}
];

function joinObjects() {
  var idMap = {};
  // Iterate over arguments
  for(var i = 0; i < arguments.length; i++) { 
    // Iterate over individual argument arrays (aka json1, json2)
    for(var j = 0; j < arguments[i].length; j++) {
       var currentID = arguments[i][j]['id'];
       if(!idMap[currentID]) {
          idMap[currentID] = {};
        }
       // Iterate over properties of objects in arrays (aka id, name, etc.)
      for(key in arguments[i][j]) {
          idMap[currentID][key] = arguments[i][j][key];
      }
    }
  }

  // Push properties of idMap into an array
  var newArray = [];
  for(property in idMap) {
    newArray.Push(idMap[property]);
  }
  return newArray;
}

var json3 = joinObjects(json1, json2);

Voici un codepen de travail.

3
Jacob Petersen

Deux one-liners:

avec lodash:

res = _(json1).concat(json2).groupBy('id').map(_.spread(_.assign)).value();

dans ES2015:

res = json2.map(x => Object.assign(x, json1.find(y => y.id == x.id)));
33
georg

La réponse d'ES2015 georg fonctionne très bien;

    json1 = [
    {id:1, test: 0},
    {id:2, test: 0},
    {id:3, test: 0},
    {id:4, test: 0},
    {id:5, test: 0}
];

json2 = [
    {id:1, test: 1},
    {id:3, test: 1},
    {id:5, test: 1}
];

json1.map(x => Object.assign(x, json2.find(y => y.id == x.id)));

résultat:

{id:1, test: 1},
{id:2, test: 0},
{id:3, test: 1},
{id:4, test: 0},
{id:5, test: 1}
6
Killian Charlez

Utilisez des boucles imbriquées pour rechercher les éléments correspondants et les fusionner.

for (var i = 0; i < json1.length; i++) {
    var id = json1[i].id;
    for (var j = 0; j < json2.length; j++) {
        if (json2[j].id = id) {
            for (var key in json2[j]) {
                json1[i][key] = json2[j][key];
            }
            break;
        }
    }
}

À la fin, json1 contiendra les éléments combinés.

Le code ci-dessus suppose que chaque élément de json2 correspond à quelque chose dans json1. S'il peut y avoir des éléments supplémentaires dans json2, vous aurez besoin d'une boucle supplémentaire par la suite pour les copier dans json1.

1
Barmar

Utilisez pourChaque et filtre nous pouvons résoudre le problème.

vehicleArray1 = [{id:1, name: "a"},{id:2, name: "b"},{id:3, name:"c"}];
vehicleArray2 = [{id:1, type: "two wheeler"},{id:2, type: "four wheeler"},{id:3, type:"six wheeler"}];
var outArr = [];
vehicleArray1.forEach(function(value) {
    var existing = vehicleArray2.filter(function(v, i) {
        return (v.id == value.id);
    });
    if (existing.length) {
        value.type = existing[0].type;
        outArr.Push(value)
    } else {
        value.type = '';
        outArr.Push(value);
    }
});
console.log(outArr)

1
KARTHIKEYAN.A

Voici un moyen de créer un index à clé id (tableau fragmenté) pour détecter et combiner des objets avec des valeurs id correspondantes, qui sont ensuite concaténés dans un tableau normal:

json3 = json1.concat(json2).reduce(function(index, obj) {
    if (!index[obj.id]) {
        index[obj.id] = obj;
    } else {
        for (prop in obj) {
            index[obj.id][prop] = obj[prop];
        }
    }
    return index;
}, []).filter(function(res, obj) {
    return obj;
});

json1 = [
    {id:1,name:'aaa'},
    {id:5,name:'ccc'},
    {id:3,name:'bbb'}
];

json2 = [
    {id:3,parameter1:'x', parameter2:'y', parameter3:'z'},
    {id:1,parameter1:'u', parameter2:'v', parameter3:'w'},
    {id:5,parameter1:'q', parameter2:'w', parameter3:'e'}
];

json3 = json1.concat(json2).reduce(function(index, obj) {
    if (!index[obj.id]) {
        index[obj.id] = obj;
    } else {
        for (prop in obj) {
            index[obj.id][prop] = obj[prop];
        }
    }
    return index;
}, []).filter(function(res, obj) {
    return obj;
});

document.write('<pre>', JSON.stringify(json3, null, 4), '</pre>');

Si votre navigateur prend en charge Object.assign :

json3 = json1.concat(json2).reduce(function(index, obj) {
    index[obj.id] = Object.assign({}, obj, index[obj.id]);
    return index;
}, []).filter(function(res, obj) {
    return obj;
});
0
trincot

Cela devrait le faire pour vous. J'espère que le code a un sens en soi. Cet exemple utilisera toujours la valeur json1 par rapport à la valeur json2 si les deux existent. Si vous voulez changer cela, vous devez changer les références d'objet (src[i] et obj[j]) dans la boucle la plus interne.

// Will take src, and merge in the contents of obj.
// Expects an array of objects for both.
// Will keep src values in favour of obj values.
function extend(src, obj) {
  
  // Loop the src, in this case json1
  for (var i = 0; i < src.length; i++) {
    
    // For every loop of json1, also loop json2
    for (var j = 0; j < obj.length; j++) {
      
      // If we have matching IDs operate on this pair
      if (src[i].id == obj[j].id) {
          
        // For every key in the object being merged in,
        // if the key exists in src, ignore new value.
        // if the doesn't exist in src, take the new value.
        for (var key in obj[j]) {
          src[i][key] = src[i].hasOwnProperty(key) ? src[i][key] : obj[j][key];
        }
        
        // We found our matching pair, so break out of the json2 loop
        break;
        
      }
      
    }
    
  }
  
  return src;
}

// -------------------------------------------

var json1 = [{
  id: 1,
  name: 'aaa'
},{
  id: 5,
  name: 'ccc'
},{
  id: 3,
  name: 'bbb'
}];

var json2 = [{
  id: 3,
  parameter1: 'x', 
  parameter2: 'y', 
  parameter3: 'z'
},{
  id: 1,
  parameter1: 'u', 
  parameter2: 'v', 
  parameter3: 'w'
},{
  id: 5,
  parameter1: 'q', 
  parameter2: 'w', 
  parameter3: 'e'
}];

var json3 = extend(json1, json2);

// ---------------------------------------------

var pre = document.getElementById('out');
pre.innerHTML = JSON.stringify(json3);
<pre id="out"></pre>

0
Luke