web-dev-qa-db-fra.com

Fusionner 2 tableaux d'objets

Regardons un exemple.

var arr1 = new Array({name: "lang", value: "German"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});

J'ai besoin de fusionner ces 2 tableaux d'objets et créer le tableau suivant.

arr3 = new Array({name: "lang", value: "German"}, {name: "age", value: "18"}, {name : "childs", value: '5'});

Existe-t-il une fonction jScript ou jQuery pour le faire?

$ .extend ne me convient pas. Il retourne

arr4 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});

Merci d'avance, Alexander.

66
Alexander
var arr3 = [];
for(var i in arr1){
   var shared = false;
   for (var j in arr2)
       if (arr2[j].name == arr1[i].name) {
           shared = true;
           break;
       }
   if(!shared) arr3.Push(arr1[i])
}
arr3 = arr3.concat(arr2);

enter image description here

26
YOU

Pour ceux qui expérimentent avec des choses modernes:

var odd = [
    { name : "1", arr: "in odd" },
    { name : "3", arr: "in odd" }
];

var even = [
    { name : "1", arr: "in even" },
    { name : "2", arr: "in even" },
    { name : "4", arr: "in even" }
];

// ----
// ES5 using Array.filter and Array.find
function merge(a, b, prop){
  var reduced = a.filter(function(aitem){
      return ! b.find(function(bitem){
          return aitem[prop] === bitem[prop];
      });
  });
  return reduced.concat(b);
}
console.log( "ES5", merge(odd, even, "name") );

// ----
// ES6 arrow functions
function merge(a, b, prop){
    var reduced =  a.filter( aitem => ! b.find ( bitem => aitem[prop] === bitem[prop]) )
  return reduced.concat(b);
}
console.log( "ES6", merge(odd, even, "name") );

// ----
// ES6 one-liner
var merge = (a, b, p) => a.filter( aa => ! b.find ( bb => aa[p] === bb[p]) ).concat(b);


console.log( "ES6 one-liner", merge(odd, even, "name") );

// Results
// ( stuff in the "b" array replaces things in the "a" array )
// [
//    {
//         "name": "3",
//         "arr": "in odd"
//     },
//     {
//         "name": "1",
//         "arr": "in even"
//     },
//     {
//         "name": "2",
//         "arr": "in even"
//     },
//     {
//         "name": "4",
//         "arr": "in even"
//     }
// ]
22
bob

J'arrive toujours ici de google et je ne suis toujours pas satisfait des réponses. VOUS répondez que c'est bien, mais ce sera plus simple et plus ordonné d'utiliser underscore.js

DEMO: http://jsfiddle.net/guya/eAWKR/

Voici une fonction plus générale qui fusionnera 2 tableaux en utilisant une propriété de leurs objets. Dans ce cas, la propriété est 'name'

var arr1 = [{name: "lang", value: "English"}, {name: "age", value: "18"}];
var arr2 = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];

function mergeByProperty(arr1, arr2, prop) {
    _.each(arr2, function(arr2obj) {
        var arr1obj = _.find(arr1, function(arr1obj) {
            return arr1obj[prop] === arr2obj[prop];
        });

        arr1obj ? _.extend(arr1obj, arr2obj) : arr1.Push(arr2obj);
    });
}

mergeByProperty(arr1, arr2, 'name');

console.log(arr1);

[{name: "lang", valeur: "allemand"}, {name: "age", valeur: "18"}, {name: "childs", valeur: '5'}]

18
guya

Fusion de deux tableaux:

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
var result=arr1.concat(arr2);
// result: [{name: "lang", value: "English"}, {name: "age", value: "18"}, {name : "childs", value: '5'}, {name: "lang", value: "German"}]

Fusion de deux tableaux sans valeurs dupliquées pour 'name':

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
var i,p,obj={},result=[];
for(i=0;i<arr1.length;i++)obj[arr1[i].name]=arr1[i].value;
for(i=0;i<arr2.length;i++)obj[arr2[i].name]=arr2[i].value;
for(p in obj)if(obj.hasOwnProperty(p))result.Push({name:p,value:obj[p]});
// result: [{name: "lang", value: "German"}, {name: "age", value: "18"}, {name : "childs", value: '5'}]
15
Andrew D.

Très simple en utilisant l'opérateur ES6 spread:

const array1 = [{a: 'HI!'}, {b: 'HOW'}]
const array2 = [{c: 'ARE'}, {d: 'YOU?'}]

const mergedArray = [ ...array1, ...array2 ]
console.log('Merged Array: ', mergedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Merged Array: [ {a: 'HI!'}, {b: 'HOW'} {c: 'ARE'}, {d: 'YOU?'} ]

6
bh4r4th

Encore une autre version utilisant reduce() method :

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});

var arr = arr1.concat(arr2).reduce(function(prev, current, index, array){ 
   
   if(!(current.name in prev.keys)) {
      prev.keys[current.name] = index;
      prev.result.Push(current);   
   } 
   else{
       prev.result[prev.keys[current.name]] = current;
   }  

   return prev;
},{result: [], keys: {}}).result;
  
document.getElementById("output").innerHTML = JSON.stringify(arr,null,2);    
<pre id="output"/>

6
Vadim Gremyachev

Avec lodash:

_.uniqBy([...arr1, ...arr2], 'name')
5
Pietro

Voici comment j'ai abordé un problème similaire dans un contexte ES6:

function merge(array1, array2, prop) {
    return array2.map(function (item2) {
        var item1 = array1.find(function (item1) {
            return item1[prop] === item2[prop];
        });
        return Object.assign({}, item1, item2);
    });
}

Remarque: cette approche ne renverra aucun élément de array1 qui n'apparaît pas dans array2.


EDIT: J'ai des scénarios dans lesquels je veux conserver les éléments qui n'apparaissent pas dans le second tableau, alors j'ai proposé une autre méthode.

function mergeArrays(arrays, prop) {
    const merged = {};

    arrays.forEach(arr => {
        arr.forEach(item => {
            merged[item[prop]] = Object.assign({}, merged[item[prop]], item);
        });
    });

    return Object.values(merged);
}

var arr1 = [
    { name: 'Bob', age: 11 },
    { name: 'Ben', age: 12 },
    { name: 'Bill', age: 13 },
];

var arr2 = [
    { name: 'Bob', age: 22 },
    { name: 'Fred', age: 24 },
    { name: 'Jack', age: 25 },
    { name: 'Ben' },
];

console.log(mergeArrays([arr1, arr2], 'name'));
5
marktuk

Vous pouvez utiliser un objet pour rassembler vos propriétés lors du remplacement des doublons, puis développer/aplatir cet objet pour le transformer en tableau. Quelque chose comme ça:

function merge(args) {
    args  = Array.prototype.slice.call(arguments);
    var o = { };
    for(var i = 0; i < args.length; ++i)
        for(var j = 0; j < args[i].length; ++j)
            o[args[i][j].name] = args[i][j].value;
    return o;
}

function expand(o) {
    var a = [ ];
    for(var p in o)
        if(o.hasOwnProperty(p))
            a.Push({ name: p, value: o[p]});
    return a;
}

var arr1 = new Array({name: "lang", value: "English"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
var arr3 = expand(merge(arr1, arr2));

Je ne sais pas si c'est le moyen le plus rapide, mais cela fonctionne pour n'importe quel nombre de tableaux d'entrée; par exemple, ceci:

var a = expand(
    merge(
        [{name: "lang", value: "English"}, {name: "age", value: "18"}],
        [{name: "childs", value: '5'}, {name: "lang", value: "German"}],
        [{name: 'lang', value: 'Pancakes'}]
    )
);

Vous donne la même chose dans a qui était dans arr3 avec "allemand" remplacé par "crêpes".

Cette approche suppose que tous vos objets ont bien sûr la même forme {name: ..., value: ...}.

Vous pouvez le voir fonctionner ici (ouvrez votre console s'il vous plaît): http://jsfiddle.net/ambiguous/UtBbB/

4
mu is too short

Avec ES6, vous pouvez le faire très facilement comme ci-dessous:

var arr1 = new Array({name: "lang", value: "German"}, {name: "age", value: "18"});
var arr2 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
var arr3 = [...arr1, ...arr2];

Sortie:

    arr3 = [
      {"name":"lang","value":"German"},
      {"name":"age","value":"18"},
      {"name":"childs","value":"5"},
      {"name":"lang","value":"German"}
    ]
4
Nguyễn Bá Vinh

Je faisais face au même problème et, sur la base de guya answer j’ai étendu la bibliothèque de soulignement et ajouté un peu plus de fonctionnalités que je demandais. Voici le Gist .

/**
 * Merges two object-like arrays based on a key property and also merges its array-like attributes specified in objectPropertiesToMerge.
 * It also removes falsy values after merging object properties.
 *
 * @param firstArray The original object-like array.
 * @param secondArray An object-like array to add to the firstArray.
 * @param keyProperty The object property that will be used to check if objects from different arrays are the same or not.
 * @param objectPropertiesToMerge The list of object properties that you want to merge. It all must be arrays.
 * @returns The updated original array.
 */
function merge(firstArray, secondArray, keyProperty, objectPropertiesToMerge) {

    function mergeObjectProperties(object, otherObject, objectPropertiesToMerge) {
        _.each(objectPropertiesToMerge, function (eachProperty) {
            object[eachProperty] = _.chain(object[eachProperty]).union(otherObject[eachProperty]).compact().value();
        });
    }

    if (firstArray.length === 0) {
        _.each(secondArray, function (each) {
            firstArray.Push(each);
        });
    } else {
        _.each(secondArray, function (itemFromSecond) {
            var itemFromFirst = _.find(firstArray, function (item) {
                return item[keyProperty] === itemFromSecond[keyProperty];
            });

            if (itemFromFirst) {
                mergeObjectProperties(itemFromFirst, itemFromSecond, objectPropertiesToMerge);
            } else {
                firstArray.Push(itemFromSecond);
            }
    });
    }

    return firstArray;
}

_.mixin({
            merge: merge
        });

J'espère que cela vous sera utile!

2
Nahuel Barrios

Solution simple

var tx = [{"id":1},{"id":2}];
var tx1 = [{"id":3},{"id":4}];


var txHistory = tx.concat(tx1)

console.log(txHistory); 
// output
 // [{"id":1},{"id":2},{"id":3},{"id":4}];
2
ngCourse

Ce problème m'a récemment posé problème et je suis venu ici avec l'espoir d'avoir une réponse, mais la réponse acceptée utilise 2 pour les boucles in que je ne préférerais pas. J'ai finalement réussi à faire le mien. Ne dépend d'aucune bibliothèque:

function find(objArr, keyToFind){
    var foundPos = objArr.map(function(ob){
        return ob.type;
    }).indexOf(keyToFind);
    return foundPos;
}

function update(arr1,arr2){
    for(var i = 0, len = arr2.length, current; i< len; i++){
        var pos = find(arr1, arr2[i].name); 
        current = arr2[i];
        if(pos !== -1) for(var key in arr2) arr1[pos][key] = arr2[key];
        else arr1[arr1.length] = current;
    } 
}

Ceci maintient également l'ordre d'arr1.

2
Amin Mohamed Ajani

Qu'en est-il de jQuery Merge?

http://api.jquery.com/jQuery.merge/

exemple jsFiddle ici: http://jsfiddle.net/ygByD/

2
321X

vous pouvez utiliser la fonction suivante

const merge = (a, b, key = "id") =>
  a.filter(elem => !b.find(subElem => subElem[key] === elem[key]))
   .concat(b);

et essaye

merge(arr1, arr2, 'name');
1
Diogo Alves

Ici, je filtre d'abord arr1 en fonction de l'élément présent dans arr2 ou non. S'il est présent, ne l'ajoutez pas au tableau résultant, sinon ajoutez-le. Et puis j'ajoute arr2 au résultat.

arr1.filter(item => {
  if (!arr2.some(item1=>item.name==item1.name)) {
    return item
  }
}).concat(arr2)
1
maulik bhatt

Utiliser lodash que vous voulez _.uniqBy

var arr3 = _.uniqBy(arr1.concat(arr2), 'name'); // es5

let arr3 = _.uniqBy([...arr1, ...arr2], 'name'); // es6

Ordre d'arr1, arr2 est important!

Voir docs https://lodash.com/docs/4.17.4#uniqBy

0
danday74

Voici un plugin jQuery que j'ai écrit pour fusionner deux tableaux d'objets par une clé. Gardez à l'esprit que cela modifie le tableau de destination sur place.

(function($) {
  $.extendObjectArray = function(destArray, srcArray, key) {
    for (var index = 0; index < srcArray.length; index++) {
      var srcObject = srcArray[index];
      var existObject = destArray.filter(function(destObj) {
        return destObj[key] === srcObject[key];
      });
      if (existObject.length > 0) {
        var existingIndex = destArray.indexOf(existObject[0]);
        $.extend(true, destArray[existingIndex], srcObject);
      } else {
        destArray.Push(srcObject);
      }
    }
    return destArray;
  };
})(jQuery);

var arr1 = [
  { name: "lang",   value: "English" },
  { name: "age",    value: "18"      }
];
var arr2 = [
  { name: "childs", value: '5'       },
  { name: "lang",   value: "German"  }
];
var arr3 = $.extendObjectArray(arr1, arr2, 'name');

console.log(JSON.stringify(arr3, null, 2));
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


Version ES6

(function($) {
  $.extendObjectArray = (destArr, srcArr, key) => {
    srcArr.forEach(srcObj => (existObj => {
      if (existObj.length) {
        $.extend(true, destArr[destArr.indexOf(existObj[0])], srcObj);
      } else {
        destArr.Push(srcObj);
      }
    })(destArr.filter(v => v[key] === srcObj[key])));
    return destArr;
  };
})(jQuery);
0
Mr. Polywhirl

De mémoire - essayez jquery extend

var arr3 = jQuery.extend(arr1,arr2....)
0
Xhalent

Basé sur la réponse de @ YOU mais en gardant la commande:

var arr3 = [];
for(var i in arr1){
   var shared = false;
   for (var j in arr2)
       if (arr2[j].name == arr1[i].name) {
           arr3.Push(arr1[j]
           shared = true;
           break;
       }
   if(!shared) arr3.Push(arr1[i])
}

for(var j in arr2){
   var shared = false;
   for (var i in arr1)
       if (arr2[j].name == arr1[i].name) {
           shared = true;
           break;
       }
   if(!shared) arr3.Push(arr2[j])
}
arr3

Je sais que cette solution est moins efficace, mais elle est nécessaire si vous souhaitez conserver l’ordre tout en mettant à jour les objets.

0
hcarreras

Si vous souhaitez fusionner les 2 tableaux, mais supprimer les objets en double, utilisez ceci . Les doublons sont identifiés sur .uniqueId de chaque objet.

function mergeObjectArraysRemovingDuplicates(firstObjectArray, secondObjectArray) {
  return firstObjectArray.concat(
    secondObjectArray.filter((object) => !firstObjectArray.map((x) => x.uniqueId).includes(object.uniqueId)),
  );
}
0
daveanderson88
merge(a, b, key) {
    let merged = [];
    a.forEach(aitem => {
        let found = b.find( bitem => aitem[key] === bitem[key]);
        merged.Push(found? found: aitem);
    });
    return merged;
}
0
Kyaw

var newArray = yourArray.concat(otherArray); console.log('Concatenated newArray: ', newArray);

0
javaScriptBeard
const extend = function*(ls,xs){
   yield* ls;
   yield* xs;
}

console.log( [...extend([1,2,3],[4,5,6])]  );
0
codemonkey