合并两个对象数组

202

让我们来看一个例子。

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 = new Array({name: "lang", value: "German"},
                     {name: "age", value: "18"},
                     {name : "childs", value: '5'});

有没有任何 JavaScript 或 jQuery 函数可以做到这一点?

$.extend 不适合我。它会返回

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

29
“{name: "lang", value: "English"}”发生了什么? - Shadow The Spring Wizard
1
我的意思是,涉及到什么逻辑?你想如何合并这些数组?从你的示例中并不清楚。 - Shadow The Spring Wizard
13
@ShadowWizard,我认为OP的意思是如果存在就更新,如果不存在就推送。 - Amin Mohamed Ajani
2
注意:此问题在2018年被根本修改,当时它被编辑为两个“lang”条目都说“德语”。最初,一个说“英语”,另一个说“德语”。这改变了问题的含义,从“每个‘名称’仅保留一个元素”变为“除非所有属性都是重复的,否则保留元素”。我正在恢复该编辑,因为某些答案将不再有意义。这是为什么应该避免对问题进行重大编辑的例子。只需进行语法和样式更改,而不更改含义。那个意见应该是一个评论,而不是一个编辑 - ToolmakerSteve
@VasiliiSuricov 我不知道你在说什么。最好不要在问题中加入无关的内容,除非你只是在开玩笑,可以随时来我的聊天室(请查看我的个人资料),我们可以在那里讨论。祝好。 - undefined
显示剩余7条评论
47个回答

2

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

function mergeArrayByProperty(arr1, arr2, prop) {
    var newArray =
        arr1.map(item => {
            if (typeof (item[prop]) !== "undefined") {
                var nItems = arr2.filter(ni => { if (typeof (ni[prop]) !== "undefined" && ni[prop] === item[prop]) return ni; });
                if (nItems.length > 0) {
                    item = Object.assign({}, item, nItems[0]);
                }
                return item;
            }
        });
    var arr2nd = arr2.flatMap(item => { return item[prop] });
    var arr1nd = arr1.flatMap(item => { return item[prop] });
    var nonDupArr = arr2nd.map(p => { if (arr1nd.includes(p) === false) return arr2.filter(i2 => { if (i2[prop] === p) return Object.assign({}, i2) })[0]; });
    return newArray.concat(nonDupArr).filter(i=>{if(i !== null)return i})
}
var arr = mergeArrayByProperty(arr1, arr2, 'name');
console.log(arr)

I know this has been answered a lot, but I thought I would share.

此代码会在第一个数组中查找重复的键,并合并第二个数组中具有相同键值的对象。如果在第二个数组中没有找到对应的值,则使用原始对象。如您所见,lang 仅在结果集中出现一次,其值为德语。


2
使用传统的 for 循环

const merge = (first, second) => {
  for(let i=0; i<second.length; i++) {
    first.push(second[i]);
  }
  return first;
}

console.log(merge([1,2,3], [4,5,6])); // [1,2,3,4,5,6]
console.log(merge(merge([1,2,3], [4,5,6]), [7,8,9])); // [1,2,3,4,5,6,7,8,9]

  1. 使用 Spread 操作符

const arr1 = [1,2,3];
const arr2 = [4,5,6];

// Merge arrays
const merged = [...arr1, ...arr2];

console.log(merged); // [1,2,3,4,5,6]

使用concat()数组方法

const arr1 = [1,2,3];
const arr2 = [4,5,6];

// Merge arrays
const merged1 = arr1.concat(arr2); // bit confusing, seems like `arr1` itself is being modified but it's not
const merged2 = [].concat(arr1, arr2); // cleaner approach

console.log(merged1); // [1,2,3,4,5,6]
console.log(merged2); // [1,2,3,4,5,6]

使用push()数组方法

const arr1A = [1,2,3];
const arr2A = [4,5,6];

const arr1B = [1,2,3];
const arr2B = [4,5,6];

const arr1C = [1,2,3];
const arr2C = [4,5,6];
const arr3C = [7,8,9];

// Merge arrays
const merged1 = arr1A.push(...arr2A);

// Merging without the ... on arr2B
const merged2 = arr1B.push(arr2B);

// Merge more than two arrays
arr1C.push(...[...arr2C, ...arr3C]);
console.log(arr1C); // [1,2,3,4,5,6,7,8,9]

console.log(merged1); // 6
console.log(arr1A); // [1,2,3,4,5,6]
console.log(arr2A); // [4,5,6]

console.log(merged2); // 4
console.log(arr1B); // [1,2,3,[4,5,6]]
console.log(arr2B); // [4,5,6]

使用reduce()数组方法

const arr1 = [1,2,3];
const arr2 = [4,5,6];

const merged = arr2.reduce((arr, item) => {
    arr.push(item);
    return arr;    
}, arr1);

console.log(merged); // [1,2,3,4,5,6]

总之,

  • 在JavaScript中,有多种合并两个或多个数组为一个数组的方法。
  • 使用spread运算符或concat()方法是最优解决方案。
  • 如果您确定要合并的所有输入都是数组,请使用spread操作符。如果不确定,请使用concat()方法。
  • 当您想要更改要合并的输入数组之一时,可以使用push()方法来合并数组。
  • 使用reduce()方法合并数组有点繁琐。

有关更多信息,请参阅详细博客此处和视频此处


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

const mergeArrOfObjects = (dataset1, dataset2) => {
    const map1 = new Map();
    dataset1.map((d1, i) => {
        map1.set(d1.name, i);
    })
    for (let d2 of dataset2) {
        if (d2 && map1.has(d2.name)) {
            dataset1[map1.get(d2.name)] = d2;
        } else if(d2){
            dataset1.push(d2);
        }
    }
    return dataset1;
};

const arr3 = mergeArrOfObjects(arr1, arr2);
console.log(arr3);

1

就我个人而言,建议尝试使用jquery extend函数。

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

抱歉。这个函数确切地返回 arr4,而不是 $.merge。最后一个也不适合我,因为它会复制对象。 - Alexander

1
根据问题,我理解您想使用一个“key”来覆盖其他属性,而不是合并它们。
interface Foo {
    name: string;
    value: string;
}

var arr1: Foo[] = [
    { name: "lang", value: "English" },
    { name: "age", value: "18" },
];

var arr2: Foo[] = [
    { name: "childs", value: "5" },
    { name: "lang", value: "German" },
];

我们可以使用 MapReduce 的组合来选择用于覆盖记录的 key
const merged: Foo[] = Array.from(
  [...arr1, ...arr2].reduce(
      (acc, curr) => acc.set(curr.name, curr),
      new Map<Foo["name"], Foo>(),
    )
    .values(),
);

// [
//   { name: "lang", value: "German" },
//   { name: "age", value: "18" },
//   { name: "childs", value: "5" },
// ];

1

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

var newArray = yourArray.concat(otherArray); console.log('合并后的newArray: ', newArray);


我同意这比Array.protype.push.apply()的答案更有意义,但它并没有像OP想要的那样进行合并。 - keithpjolley
如果您有两个合并的对象数组,则无法使用“concat”获得上述输出。请查看此链接https://jsfiddle.net/jahanzaibaslam/z22n5tuo/。 - Jahanzaib Aslam

1

我发布这篇文章是因为与之前的答案不同,这个是通用的,没有外部库,O(n)复杂度,实际上过滤了重复项并保留了原始顺序(通过将最后匹配的元素放置在第一次出现的位置):

function unique(array, keyfunc) {
    return array.reduce((result, entry) => {
        const key = keyfunc(entry)
        if(key in result.seen) {
            result.array[result.seen[key]] = entry
        } else {
            result.seen[key] = result.array.length
            result.array.push(entry)
        }
        return result
    }, { array: [], seen: {}}).array
}

使用方法:

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 = unique([...arr1, ...arr2], x => x.name)
/* arr3 == [ 
    {name: "lang", value: "German"}, 
    {name: "age", value: "18"},
    {name: "childs", value: "5"}
]*/

1
let mergeArray = arrA.filter(aItem => !arrB.find(bItem => aItem.name === bItem.name))

2
添加一些代码解释会更好。 - keikai

1

这里首先根据 arr2 中的元素来过滤 arr1。如果存在,则不将其添加到结果数组中,否则添加。然后将 arr2 添加到结果中。

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

请提供您答案的解释,这样如果其他人阅读问题和答案,就可以轻松理解。 - Mittal Patel
虽然这个答案可能是正确和有用的,但最好还是附上一些解释来说明它如何帮助解决问题。如果将来发生了变化(可能与此无关),导致它停止工作并且用户需要了解它曾经是如何工作的,这将特别有用。 - Erty Seidohl
谢谢大家。我更新了解决方案的描述。如果看起来正确,请点赞 :) - maulik bhatt

1
只需使用helprjs
const arr1 = [{ id: 1, name: 'Jack'}, { id: 2, name: 'Jack'}];
const arr2 = [{ id: 2, name: 'Jane'}, { id: 3, name: 'Rod'}];

mergeArrays(arr1, arr2, "name");
// [{ id: 1, name: 'Jack'}, { id: 2, name: 'Jane'}, { id: 3, name: 'Rod'}];

mergeArrays(arr1, arr2, "id");
// [{ id: 1, name: 'Jack'}, { id: 2, name: 'Jack'}, { id: 3, name: 'Rod'}];

请查看 demo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接