Объединить 2 массива объектов - PullRequest
76 голосов
/ 22 августа 2011

Давайте рассмотрим пример.

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

Мне нужно объединить эти 2 массива объектов и создать следующий массив.

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

Есть ли какая-либо функция jScript или jQuery для этого?

$. Расширение меня не устраивает. Возвращает

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

Спасибо заранее, Александр.

Ответы [ 26 ]

5 голосов
/ 20 апреля 2018

Вот как я справился с подобной проблемой в контексте 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);
    });
}

Примечание. Этот подход не возвращает никаких элементов из массива1, которые не отображаются в массиве 2.


РЕДАКТИРОВАТЬ: У меня есть несколько сценариев, в которых я хочу сохранить элементы, которые не отображаются во втором массиве, поэтому я нашел другой метод.

4 голосов
/ 22 августа 2011

Вы можете использовать объект для сбора ваших свойств при замене дубликатов, а затем развернуть / выровнять этот объект обратно в массив.Примерно так:

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

Я не знаю, является ли это самым быстрым способом, но он работает для любого числа входных массивов;например, это:

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

Дает вам то же самое в a, что было в arr3 с заменой «German» на «Pancakes».

Этот подход предполагает, чтовсе ваши объекты имеют одинаковую форму {name: ..., value: ...}.

Вы можете увидеть, как она работает здесь (откройте консоль, пожалуйста): http://jsfiddle.net/ambiguous/UtBbB/

3 голосов
/ 10 августа 2018

Простое решение

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 голосов
/ 22 августа 2011

А как насчет jQuery Merge?

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

jsFiddle пример здесь: http://jsfiddle.net/ygByD/

2 голосов
/ 20 июня 2014

Я столкнулся с той же проблемой и, основываясь на guya answer Я расширил библиотеку подчеркивания, а также добавил немного больше необходимых мне функций.Вот Гист .

/**
 * 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
        });

Надеюсь, это будет полезно!Привет!

2 голосов
/ 28 сентября 2016

Недавно я был озадачен этой проблемой, и я пришел сюда с надеждой получить ответ, но в принятом ответе используется 2 для циклов in, которые я бы не предпочел. Мне наконец удалось сделать свой собственный. Не зависит ни от какой библиотеки:

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

Это также поддерживает порядок arr1.

1 голос
/ 06 августа 2018

вы можете использовать следующую функцию

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

и попробуйте

merge(arr1, arr2, 'name');
1 голос
/ 06 июля 2018

Здесь я сначала фильтрую arr1 на основе элемента, присутствующего в arr2 или нет.Если он присутствует, не добавляйте его в результирующий массив, иначе добавьте.И тогда я добавляю arr2 к результату.

arr1.filter(item => {
  if (!arr2.some(item1=>item.name==item1.name)) {
    return item
  }
}).concat(arr2)
0 голосов
/ 07 декабря 2016

На основании ответа @ ВЫ, но с соблюдением порядка:

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

Я знаю, что это решение менее эффективно, но оно необходимо, если вы хотите сохранить порядок и обновлять объекты.

0 голосов
/ 16 июля 2018
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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...