Объединить 2 массива объектов
Давайте посмотрим на пример.
var arr1 = new Array({name: "lang", value: "English"}, {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'});
Есть ли какая-либо функция JavaScript или jQuery для этого?
$.extend
меня не устраивает. Возвращает
arr4 = new Array({name : "childs", value: '5'}, {name: "lang", value: "German"});
Ответы
Ответ 1
Если вы хотите объединить 2 массива объектов в JavaScript. Вы можете использовать этот трюк с одной строкой
Array.prototype.push.apply(arr1,arr2);
Пример
var arr1 = [{name: "lang", value: "English"},{name: "age", value: "18"}];
var arr2 = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];
Array.prototype.push.apply(arr1,arr2);
console.log(arr1); // final merged result will be in arr1
Вывод:
[{"name":"lang","value":"English"},
{"name":"age","value":"18"},
{"name":"childs","value":"5"},
{"name":"lang","value":"German"}]
Ответ 2
Для тех, кто экспериментирует с современными вещами:
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"
// }
// ]
Ответ 3
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]()
Ответ 4
С ES6 вы можете сделать это очень просто, как показано ниже:
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];
Выход:
arr3 = [
{"name":"lang","value":"German"},
{"name":"age","value":"18"},
{"name":"childs","value":"5"},
{"name":"lang","value":"German"}
]
Ответ 5
Обновление 12 октября 2019 г.
Новая версия основана только на более новом Javascript и не требует какой-либо сторонней библиотеки.
const mergeByProperty = (target, source, prop) => {
source.forEach(sourceElement => {
let targetElement = target.find(targetElement => {
return sourceElement[prop] === targetElement[prop];
})
targetElement ? Object.assign(targetElement, sourceElement) : target.push(sourceElement);
})
}
var target /* arr1 */ = [{name: "lang", value: "English"}, {name: "age", value: "18"}];
var source /* arr2 */ = [{name : "childs", value: '5'}, {name: "lang", value: "German"}];
mergeByProperty(target, source, 'name');
console.log(target)
Этот ответ стареет, в наше время такие библиотеки, как lodash и underscore, гораздо меньше нужны.
В этой новой версии массив target (arr1) - это тот, с которым работали и хотят быть в курсе событий.
Массив source (arr2) - это источник новых данных, и мы хотим, чтобы они были объединены с нашим target массивом.
Мы перебираем массив source в поисках новых данных, и для каждого объекта, который еще не найден в нашем массиве target, мы просто добавляем этот объект с помощью target.push(sourceElement )
Если на основании нашего ключевого свойства ('name') объект уже находится в нашем целевом массиве - мы обновляем его свойства и значения с помощью Object.assign(targetElement, sourceElement).
Наша "цель" всегда будет одним и тем же массивом с обновленным содержимым.
Старый ответ с использованием подчеркивания или lodash
Я всегда прибываю сюда из Google, и я всегда не удовлетворяюсь от ответов. ВЫ ответите хорошо, но с underscore.js будет проще и удобнее
ДЕМО: http://jsfiddle.net/guya/eAWKR/
Вот более общая функция, которая объединит 2 массива, используя свойство их объектов. В данном случае это свойство '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", значение: "German"}, {name: "age", значение: "18"}, {name: "childs", значение: '5'}]
Ответ 6
Объединение двух массивов:
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"}]
Объединение двух массивов без дублированных значений для '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'}]
Ответ 7
Самый простой способ - с помощью некоторой магии ES6:
Объединить два с дубликатами:
const a = [{a: 1}, {b: 2}]
const b = [{a: 1}]
const result = a.concat(b) // [{a: 1}, {b: 2}, {a: 1}]
Без дубликатов это то же самое, что и выше плюс:
const distinct = [...new Set(result.map(item => item.YOUR_PROP_HERE))]
Ответ 8
Очень просто с помощью оператора распространения ES6:
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>
Ответ 9
Еще одна версия, использующая 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"/>
Ответ 10
С lodash:
_.uniqBy([...arr1, ...arr2], 'name')
Ответ 11
Вот как я решил аналогичную проблему в контексте 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.
РЕДАКТИРОВАТЬ: У меня есть несколько сценариев, где я хочу сохранить элементы, которые не появляются во втором массиве, поэтому я предложил другой метод.
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'));
Ответ 12
Вы можете использовать объект для сбора своих свойств при замене дубликатов, а затем развернуть/спрятать этот объект обратно в массив. Что-то вроде этого:
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" заменено "Блины".
Этот подход предполагает, что ваши объекты все имеют ту же форму {name: ..., value: ...}
, конечно.
Вы можете увидеть, как он работает здесь (откройте консоль): http://jsfiddle.net/ambiguous/UtBbB/
Ответ 13
Простое решение
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}];
Ответ 14
Как насчет слияния jQuery?
http://api.jquery.com/jQuery.merge/
Пример jsFiddle здесь: http://jsfiddle.net/ygByD/
Ответ 15
Я столкнулся с той же проблемой и на основе guya answer. Я расширил библиотеку подчёркивания, а также добавил немного больше функциональности, которую я требовал. Здесь 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
});
Надеюсь, это будет полезно!
Привет!
Ответ 16
Недавно я столкнулся с этой проблемой, и я пришел сюда с надеждой получить ответ, но принятый ответ использует 2 для циклов, которые я бы не предпочел. Наконец, мне удалось сделать свой собственный. Не зависит от какой-либо библиотеки:
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.
Ответ 17
Здесь я сначала фильтрую arr1
на основе элемента, присутствующего в arr2
или нет. Если он присутствует, не добавляйте его в результирующий массив, иначе добавьте. И тогда я добавляю arr2
к результату.
arr1.filter(item => {
if (!arr2.some(item1=>item.name==item1.name)) {
return item
}
}).concat(arr2)
Ответ 18
Вы могли бы использовать следующую функцию
const merge = (a, b, key = "id") =>
a.filter(elem => !b.find(subElem => subElem[key] === elem[key]))
.concat(b);
и попробовать
merge(arr1, arr2, 'name');
Ответ 19
Сверху моей головы - попробуйте jquery extend
var arr3 = jQuery.extend(arr1,arr2....)
Ответ 20
var newArray = yourArray.concat(otherArray);
console.log('Concatenated newArray: ', newArray);
Ответ 21
На основании ответа @YOU, но сохраняя порядок:
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
Я знаю, что это решение менее эффективно, но оно необходимо, если вы хотите сохранить заказ и все еще обновлять объекты.
Ответ 22
Здесь плагин jQuery, который я написал, чтобы слить два массива объектов с помощью ключа. Имейте в виду, что это изменяет массив назначения на месте.
(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>
Ответ 23
Используя lodash вы хотите _.uniqBy
var arr3 = _.uniqBy(arr1.concat(arr2), 'name'); // es5
let arr3 = _.uniqBy([...arr1, ...arr2], 'name'); // es6
Порядок arr1, arr2 имеет значение!
См. docs https://lodash.com/docs/4.17.4#uniqBy
Ответ 24
const extend = function*(ls,xs){
yield* ls;
yield* xs;
}
console.log( [...extend([1,2,3],[4,5,6])] );
Ответ 25
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;
}
Ответ 26
Если вы хотите объединить 2 массива, но удалить повторяющиеся объекты, используйте это. Дубликаты идентифицируются на .uniqueId
каждого объекта
function mergeObjectArraysRemovingDuplicates(firstObjectArray, secondObjectArray) {
return firstObjectArray.concat(
secondObjectArray.filter((object) => !firstObjectArray.map((x) => x.uniqueId).includes(object.uniqueId)),
);
}
Ответ 27
Попробуйте это:
var a = [{"a":20, "b":10,"c":"c","d":"asd","f":"any"}]
var b = [{"a":20, "b":10,"c":"c", "e":"nan","g":10200}]
var p = []
_.map(a, function(da){
var chk = _.filter(b, function(ds){
return da.a ===ds.a
})[0]
p.push(_.extend(da, chk))
})
console.log(p)
OutPut будет:
[{
"a": 20,
"b": 10,
"c": "c",
"d": "asd",
"f": "any",
"e": "nan",
"g": 10200
}]