我有两个JavaScript数组:

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

我希望输出为:

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

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

如何在JavaScript中合并两个数组,以便从每个数组中只获得唯一的项目,其顺序与它们插入原始数组的顺序相同?


当前回答

给定两个没有重复的简单类型的排序数组,这将在O(n)时间内合并它们,并且输出也将被排序。

function merge(a, b) {
    let i=0;
    let j=0;
    let c = [];
    for (;;) {
        if (i == a.length) {
            if (j == b.length) return c;
            c.push(b[j++]);
        } else if (j == b.length || a[i] < b[j]) {
            c.push(a[i++]);
        } else {
            if (a[i] == b[j]) ++i;   // skip duplicates
            c.push(b[j++]);
        }
    }
}

其他回答

这里是关于计算时间方面最有效的方法。它还保持元素的初始顺序。

首先过滤第二个数组中的所有重复项,然后将剩下的连接到第一个数组。

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

这里有一个稍微不同的循环。通过Chrome最新版本中的一些优化,它是解决两个数组联合的最快方法(Chrome 38.0.2111)。

http://jsperf.com/merge-two-arrays-keeping-only-unique-values

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

var arr = array1.concat(array2),
  len = arr.length;

while (len--) {
  var itm = arr[len];
  if (array3.indexOf(itm) === -1) {
    array3.unshift(itm);
  }
}

while循环:约589k ops/s滤波器:~44k ops/slodash:30.8万次/秒对于循环:225k操作/秒

一条评论指出,我的一个设置变量导致我的循环领先于其他循环,因为它不需要初始化一个空数组来写入。我同意这一点,所以我已经将测试重写为公平的环境,并包含了一个更快的选项。

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/52

let whileLoopAlt = function (array1, array2) {
    const array3 = array1.slice(0);
    let len1 = array1.length;
    let len2 = array2.length;
    const assoc = {};

    while (len1--) {
        assoc[array1[len1]] = null;
    }

    while (len2--) {
        let itm = array2[len2];

        if (assoc[itm] === undefined) { // Eliminate the indexOf call
            array3.push(itm);
            assoc[itm] = null;
        }
    }

    return array3;
};

在另一种解决方案中,我结合了一个答案的关联数组解决方案,以消除循环中的.indexOf()调用,该调用通过第二个循环大大降低了速度,并包含了其他用户在其答案中建议的一些其他优化。

这里的最高答案是每个值(i-1)都有一个双循环,但速度仍然很慢。lodash仍然做得很好,我仍然会向任何不介意在项目中添加库的人推荐它。对于那些不想这样做的人来说,我的while循环仍然是一个很好的答案,过滤器的答案在这里表现得很好,在我的测试中击败了最新的Canary Chrome(44.0.2360)。

如果你想加快速度,看看迈克和丹·斯托克的答案。在经历了几乎所有可行的答案之后,这些是迄今为止所有结果中最快的。

这是我的第二个答案,但我相信最快的答案是什么?我希望有人帮我检查并在评论中回复。

我的第一次尝试达到了99k操作/秒,这一次的复测是390k操作/每秒,而另一次领先的jsperf测试是140k(对我来说)。

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/26

这次我尝试尽可能减少阵列交互,看起来我获得了一些性能。

function findMerge(a1, a2) {
    var len1 = a1.length;

    for (var x = 0; x < a2.length; x++) {
        var found = false;

        for (var y = 0; y < len1; y++) {
            if (a2[x] === a1[y]) {
                found = true;
                break;
            }
        }

        if(!found){
            a1.push(a2.splice(x--, 1)[0]);
        }
    }

    return a1;
}

编辑:我对我的功能做了一些更改,与jsperf站点上的其他功能相比,性能非常出色。

我在尝试做同样的事情时遇到了这个帖子,但我想尝试一些不同的东西。我刚刚完成了下面的功能。我还有另一个变量“compareKeys”(键数组),用于进行浅对象比较。我将来可能会把它改成一个函数。

无论如何,我没有包括那部分,因为它不适用于这个问题。我还将代码放入jsperf中。编辑:我修复了jsperf中的条目。与140k相比,我的函数的运算速度约为99k次/秒。

对于代码:我首先创建一个可用索引数组,然后通过迭代第一个数组来消除它们。最后,我通过使用两个数组之间不匹配的缩减索引数组来插入“剩余部分”。

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/26

function indiceMerge(a1, a2) {
    var ai = [];
    for (var x = 0; x < a2.length; x++) {
        ai.push(x)
    };

    for (var x = 0; x < a1.length; x++) {
        for (var y = 0; y < ai.length; y++) {
            if (a1[x] === a2[ai[y]]) {
                ai.splice(y, 1);
                y--;
            }
        }
    }

    for (var x = 0; x < ai.length; x++) {
        a1.push(a2[ai[x]]);
    }

    return a1;
}

这很简单,可以用jQuery在一行中完成:

var arr1 = ['Vijendra', 'Singh'], arr2 =['Singh', 'Shakya'];

$.unique(arr1.concat(arr2))//one line

["Vijendra", "Singh", "Shakya"]