如何在JavaScript中合并两个数组并去重

1962

我有两个 JavaScript 数组:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

我希望输出结果是:

var array3 = ["Vijendra","Singh","Shakya"];

输出数组应该删除重复的单词。

我如何在JavaScript中合并两个数组,以便获取每个数组中唯一的项,并以它们插入原始数组的相同顺序返回?


32
在发布新答案之前,请考虑此问题已经有75个以上的答案。请确保您的答案提供的信息不在现有答案中。 - janniks
5
结果为 [1, 2, 3, 4],这行代码使用了 ES6 的 Set 数据结构和展开运算符将两个数组去重合并。 - Denis Giffeler
如果您想要一个更通用的解决方案,也包括深度合并,请查看这个问题。一些答案也涵盖了数组。 - Martin Braun
简而言之 - 合并数组 (ba) : a=a.concat(b); 从数组 a 中删除重复项 (就地操作) : a=a.filter((i,p)=>a.indexOf(i)===p); - ashleedawg
如果你不想再有更多答案,可以关闭问题。 - Janos Vinceller
问题仍然开放,等待不同、创新、前沿的答案。这也是免责声明的原因。 - Rodrigo Rodrigues
92个回答

3

使用筛选器的最简单解决方案:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var mergedArrayWithoutDuplicates = array1.concat(
  array2.filter(seccondArrayItem => !array1.includes(seccondArrayItem))
);

2

假设原始数组不需要去重,这样做应该非常快,保留原始顺序,并且不修改原始数组...

function arrayMerge(base, addendum){
    var out = [].concat(base);
    for(var i=0,len=addendum.length;i<len;i++){
        if(base.indexOf(addendum[i])<0){
            out.push(addendum[i]);
        }
    }
    return out;
}

使用方法:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = arrayMerge(array1, array2);

console.log(array3);
//-> [ 'Vijendra', 'Singh', 'Shakya' ]

2

看起来在我的测试中被接受的答案是最慢的;

请注意,我正在通过合并两个对象数组。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<button type='button' onclick='doit()'>do it</button>
<script>
function doit(){
    var items = [];
    var items2 = [];
    var itemskeys = {};
    for(var i = 0; i < 10000; i++){
        items.push({K:i, C:"123"});
        itemskeys[i] = i;
    }

    for(var i = 9000; i < 11000; i++){
        items2.push({K:i, C:"123"});
    }

    console.time('merge');
    var res = items.slice(0);

    //method1();
    method0();
    //method2();

    console.log(res.length);
    console.timeEnd('merge');

    function method0(){
        for(var i = 0; i < items2.length; i++){
            var isok = 1;
            var k = items2[i].K;
            if(itemskeys[k] == null){
                itemskeys[i] = res.length;
                res.push(items2[i]);
            }
        }
    }

    function method1(){
        for(var i = 0; i < items2.length; i++){
            var isok = 1;
            var k = items2[i].K;

            for(var j = 0; j < items.length; j++){
                if(items[j].K == k){
                    isok = 0;
                    break;
                }
            }

            if(isok) res.push(items2[i]);
        }  
    }

    function method2(){
        res = res.concat(items2);
        for(var i = 0; i < res.length; ++i) {
            for(var j = i+1; j < res.length; ++j) {
                if(res[i].K === res[j].K)
                    res.splice(j--, 1);
            }
        }
    }
}
</script>
</body>
</html>

2

使用 Lodash

我发现 @GijsjanB 的回答很有用,但我的数组包含了许多属性的对象,因此我必须使用其中一个属性来去重。

这是使用 lodash 的解决方案:

userList1 = [{ id: 1 }, { id: 2 }, { id: 3 }]
userList2 = [{ id: 3 }, { id: 4 }, { id: 5 }]
// id 3 is repeated in both arrays

users = _.unionWith(userList1, userList2, function(a, b){ return a.id == b.id });

// users = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }]

你传递给第三个参数的函数有两个参数(两个元素),必须返回true,如果它们相等。


2
在Dojo 1.6及以上版本中,
var unique = []; 
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = array1.concat(array2); // Merged both arrays

dojo.forEach(array3, function(item) {
    if (dojo.indexOf(unique, item) > -1) return;
    unique.push(item); 
});

更新

请查看可工作的代码。

http://jsfiddle.net/UAxJa/1/


1
为什么只使用Dojo的forEach函数呢? - Lajos Mészáros
另外,您不需要合并这两个数组。只需循环遍历第二个数组,并在第一个数组中不存在它们的值时将它们添加进去即可。 - Lajos Mészáros
1
@MészárosLajos 不,我绝不会仅为forEach函数加载Dojo。我发布这篇文章是为了如果有人已经在使用Dojo,可以参考一下。至于优化,除非你知道第一个数组包含唯一值,否则不可能 - Richard Ayotte

2

以下是关于计算时间最有效的方法,同时保持元素的初始顺序。

首先从第二个数组中筛选出所有重复项,然后将剩余的内容连接到第一个数组中。

var a = [1,2,3];
var b = [5,4,3];
var c = a.concat(b.filter(function(i){
    return a.indexOf(i) == -1;
}));
console.log(c); // [1, 2, 3, 5, 4]

这里是略微改进(更快)的版本,但有一个缺点,那就是数组中不能缺少值:

var i, c = a.slice(), ci = c.length;
for(i = 0; i < b.length; i++){
    if(c.indexOf(b[i]) == -1)
        c[ci++] = b[i];
}

我不明白为什么这比LiraNuna的解决方案更有效率。你们都使用了concat函数,并且为了找到唯一元素,你们都具有O(n^2)的时间复杂度。然而,你的解决方案代码行数较少,更易于阅读。 - Anton Gildebrand
@AntonGildebrand 那里有更多无用的迭代。你可以在这里查看比较(打开浏览器控制台查看):http://jsbin.com/wabahuha/1/edit?js,输出 - AlexTR

2

合并任意数量的数组或非数组,并保持唯一性:

function flatMerge() {
    return Array.prototype.reduce.call(arguments, function (result, current) {
        if (!(current instanceof Array)) {
            if (result.indexOf(current) === -1) {
                result.push(current);
            }
        } else {
            current.forEach(function (value) {
                console.log(value);
                if (result.indexOf(value) === -1) {
                    result.push(value);
                }
            });
        }
        return result;
    }, []);
}

flatMerge([1,2,3], 4, 4, [3, 2, 1, 5], [7, 6, 8, 9], 5, [4], 2, [3, 2, 5]);
// [1, 2, 3, 4, 5, 7, 6, 8, 9]

flatMerge([1,2,3], [3, 2, 1, 5], [7, 6, 8, 9]);
// [1, 2, 3, 5, 7, 6, 8, 9]

flatMerge(1, 3, 5, 7);
// [1, 3, 5, 7]

2
你可以使用 loadash unionWith - _.unionWith([arrays], [comparator])。这个方法类似于 _.union 方法,但是它接受一个比较器,用于比较数组的元素。结果值是从第一个出现该值的数组中选择的。比较器使用两个参数进行调用:(arrVal, othVal)。

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
 
var array3 = _.unionWith(array1, array2, _.isEqual);
console.log(array3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>


重复问题已经通过相同的方式回答了:https://dev59.com/BHI-5IYBdhLWcg3w-9wK#46135706 - gdbdable
@gdbdable 这个答案不同,它是改进。 - Kamil Kiełczewski

2

这里有另一个使用Set的巧妙解决方案:

const o1 = {a: 1};
const arr1 = ['!@#$%^&*()', 'gh', 123, o1, 1, true, undefined, null];
const arr2 = ['!@#$%^&*()', 123, 'abc', o1, 0x001, true, void 0, 0];

const mergeUnique = (...args) => [ ...new Set([].concat(...args)) ];

console.log(mergeUnique(arr1, arr2));


2

关注效率,但希望在行内完成

const s = new Set(array1);
array2.forEach(a => s.add(a));
const merged_array = [...s]; // optional: convert back in array type

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